
// Copyright (C) 2009-2012 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//  
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
using System.Windows.Forms;

using Derm.OpenGL;

namespace Derm.Render
{
	/// <summary>
	/// Rendering context.
	/// </summary>
	/// <remarks>
	/// <para>
	/// A RenderContext represents an attachment to the graphic operations. It actually store the graphic state, which determine the
	/// graphical pipeline results.
	/// </para>
	/// <para>
	/// To construct a RenderContext instance, it is necessary a device context. The device context is a OS handle which represents a
	/// specific graphical device. You can note that there are constructors which does not require a device context parameter: in this cases
	/// a common device context is used implicitly.
	/// </para>
	/// <para>
	/// If it available, it is possible to request a particoular OpenGL implementation. To check availability, <see cref="RenderContext.Capabilities.CreateContext"/>
	/// or <see cref="RenderContext.Capabilities.CreateContextProfile"/> indicates whether it is possible to select a particoular OpenGL implementation
	/// only for a RenderContext instance.
	/// 
	/// Respect a particoular version requested, it is possible that the current OpenGL implementation returns a context that doesn't have the exact
	/// OpenGL version requested. In this cases it is assured that the OpenGL version requested it is implemented (i.e. actual OpenGL version is a
	/// superset of the requested one).
	/// 
	/// Without those OpenGL extensions, it won't be possible to request a different OpenGL implementation from the current one, which is queriable
	/// by accessing to <see cref="RenderContext.CurrentCaps"/>.
	/// </para>
	/// <para>
	/// It is possible to share resources with other RenderContext instances by specifying a RenderContext parameter at construction time. The
	/// resources could be shared are listed in <see cref="IRenderResource"/>. There can be sharing compatibility issues by sharing resources
	/// having different OpenGL implementations.
	/// 
	/// As generale rule, when an OpenGL version introduce a new object space class not implemented by another version, those two OpenGL version
	/// cannot share object spaces.
	/// </para>
	/// <para>
	/// RenderContext define OpenGL implementation capabilities with the type <see cref="RenderContext.Capabilities"/>. This type collection
	/// useful information about a specific OpenGL implementation. It defines general information, implementation limits and extension support.
	/// 
	/// RenderContext exposes the current implementation capabilities by the static property <see cref="RenderContext.CurrentCaps"/>. This information
	/// is static, and it represent the most extended implementation currently available. Normally this property is not used for testing OpenGL support
	/// and limits, since this information is dependent on the current context, which could not be a RenderContext with the current OpenGL version (because
	/// it is possible to request a specific OpenGL implementation version).
	/// 
	/// Since each OpenGL implementation version can support any OpenGL extension combination, each RenderContext has its own OpenGL support, which could
	/// differ from the current OpenGL support.
	/// 
	/// Because this, all methods which depends on OpenGL support take a parameter of type RenderContext: that parameter is used to test effective support
	/// and limits for the specific OpenGL context. Testing OpenGL context capabilities by means of <see cref="RenderContext.CurrentCaps"/> could lead to
	/// invalid operations since those capabilities are not referred to the currently bound context.
	/// </para>
	/// <para>
	/// Since the device context is constructed by specifying a device context, it is able to detect ... remove public interface!
	/// </para>
	/// <para>
	/// Before any operation, the RenderContext has to be current. Only one current context per thread is allowed, but multiple context can made current on
	/// a thread one at time. Once a RenderContext is current on a thread, it is possible to issue rendering commands, and the rendering commands result is
	/// dependent on the current RenderContext.
	/// 
	/// Issuing rendering commands without having a current context on the thread will lead to exceptions.
	/// 
	/// A RenderContext is made current by calling <see cref="MakeCurrent(System.Boolean)"/> or <see cref="MakeCurrent(System.IntPtr,System.Boolean)"/>. It is
	/// possible to check the RenderContext currency by calling <see cref="IsCurrent()"/>, or getting the current RenderContext for the thread
	/// by calling <see cref="GetCurrentContext"/>.
	/// </para>
	/// </remarks>
	public sealed class RenderContext : IDisposable
	{
		#region Constructors

		/// <summary>
		/// Static RenderContext constructor.
		/// </summary>
		/// <remarks>
		/// This method shall create an initial OpenGL context for querying extensions; then shall destroy it keeping track of extensions. Future RenderContext can
		/// use the inspected extensions to provide every acceleration as possible.
		/// </remarks>
		/// <exception cref="InvalidOperationException">
		/// Exception throw in the case the <see cref="System.Windows.Forms.Form"/> created cannot be used for getting a valid device context.
		/// </exception>
		static RenderContext()
		{
			// Create common hidden window
			HiddenWindow = new System.Windows.Forms.Form();
			// Create basic context
			IntPtr rContext;
			IDeviceContext rDevice;

			switch (Environment.OSVersion.Platform) {
				case PlatformID.Unix:
					rContext = CreateX11SimpleContext(HiddenWindow, out rDevice);
					break;
				case PlatformID.Win32Windows:
				case PlatformID.Win32NT:
					rContext = CreateWinSimpleContext(HiddenWindow, out rDevice);
					break;
				default:
					throw new NotSupportedException("unable to create OpenGL context on platform " + Environment.OSVersion.ToString());
			}

			// Query OpenGL informations
			bool current = Gl.MakeContextCurrent(rDevice, rContext);
			if (current == false)
				throw new Exception("unable to make current");
			Debug.Assert(RenderException.CheckErrors() == true);

			// Initialize OpenGL implementations descriptions
			RegisterSupportedOpenGLVersions();

			// Obtain current OpenGL implementation
			string glVersion;

			glVersion = Gl.GetString(Gl.VERSION);
			Debug.Assert(RenderException.CheckErrors() == true);
			sCurrentGLVersion = ParseGLVersion(glVersion);
			sLog.Debug("Current OpenGL implemented: {0}", glVersion);

			// Obtain current OpenGL Shading Language version
			string glslVersion;
			glslVersion = Gl.GetString(Gl.SHADING_LANGUAGE_VERSION);
			Debug.Assert(RenderException.CheckErrors() == true);
			sCurrentShadingGLVersion = ParseGLSLVersion(glslVersion);
			sLog.Debug("Current OpenGL Shading Language implemented: {0}", glslVersion);

			// Query OpenGL extensions (current OpenGL implementation, CurrentCaps)
			sRenderCaps = QueryOpenGLInfo(rDevice, null);
			// Cache current OpenGL capabilities
			sRenderCapsDb[sCurrentGLVersion] = sRenderCaps;

			// Detroy context
			if (Gl.DeleteContext(rDevice, rContext) == false)
				throw new Exception("unable to delete OpenGL context");


			// Initialize default shader library
			ShaderLibrary.Touch();
		}

		/// <summary>
		/// Creates an OpenGL context from a Windows platform.
		/// </summary>
		/// <param name="window">
		/// A <see cref="Form"/>
		/// </param>
		/// <returns>
		/// A <see cref="IntPtr"/>
		/// </returns>
		private static IntPtr CreateWinSimpleContext(Form window, out IDeviceContext rDevice)
		{
			IntPtr rContext;

			// As usual, use GetDC
			WindowsDeviceContext winDeviceContext = new WindowsDeviceContext(window);

			rDevice = winDeviceContext;

			// Define most compatible pixel format
			Wgl.PIXELFORMATDESCRIPTOR pfd;
			int pFormat;

			// Describe the pixel format fundamentals
			pfd.nVersion = 1; pfd.nSize = (short)Marshal.SizeOf(typeof(Wgl.PIXELFORMATDESCRIPTOR));
			pfd.iLayerType = Wgl.PFD_MAIN_PLANE;
			pfd.dwFlags = (Wgl.PFD_SUPPORT_OPENGL|Wgl.PFD_DOUBLEBUFFER|Wgl.PFD_DRAW_TO_WINDOW);
			pfd.iPixelType = Wgl.PFD_TYPE_RGBA;
			pfd.dwLayerMask = 0; pfd.dwVisibleMask = 0; pfd.dwDamageMask = 0;
			pfd.cAuxBuffers = 0;
			pfd.bReserved = 0;
			pfd.cColorBits = 32;
			pfd.cRedBits = 0; pfd.cRedShift = 0;
			pfd.cGreenBits = 0; pfd.cGreenShift = 0;
			pfd.cBlueBits = 0; pfd.cBlueShift = 0;
			pfd.cAlphaBits = 0; pfd.cAlphaShift = 0;
			pfd.cDepthBits = 0;
			pfd.cStencilBits = 0;
			pfd.cAccumBits = 0;
			pfd.cAccumRedBits = 0; pfd.cAccumGreenBits = 0; pfd.cAccumBlueBits = 0; pfd.cAccumAlphaBits = 0;

			// Find pixel format match
			if ((pFormat = Wgl.GdiChoosePixelFormat(winDeviceContext.WindowHandle, out pfd)) == 0)
				throw new Exception();

			if (pfd.cColorBits == 0)
				throw new Exception("unable to select valid pixel format");
			// Set pixel format before creating OpenGL context
			if (Wgl.GdiSetPixelFormat(winDeviceContext.WindowHandle, pFormat, out pfd) == false)
				throw new Exception("unable to set valid pixel format");

			// Create a dummy OpenGL context to retrieve initial informations.
			if ((rContext = Wgl.CreateContext(winDeviceContext.WindowHandle)) == IntPtr.Zero)
				throw new Exception("unable to create OpenGL context");

			return (rContext);
		}

		/// <summary>
		/// Creates an OpenGL context from a Windows platform.
		/// </summary>
		/// <param name="window">
		/// A <see cref="Form"/>
		/// </param>
		/// <returns>
		/// A <see cref="IntPtr"/>
		/// </returns>
		private static IntPtr CreateX11SimpleContext(Form window, out IDeviceContext rDevice)
		{
			IntPtr rContext;

			IntPtr display = Glx.XOpenDisplay(IntPtr.Zero);
			if (display == IntPtr.Zero)
				throw new InvalidOperationException("unable to connect to server");

			int screen = Glx.XDefaultScreen(display);

			int[] attributes = new int[] {
				Glx.RENDER_TYPE, (int)Glx.RGBA_BIT,
				0
			};

			// Get basic visual
			IntPtr visual;

			unsafe {
				int[] choosenConfigCount = new int[1];
				IntPtr *choosenConfig = Glx.ChooseFBConfig(display, screen, attributes, ref choosenConfigCount);

				if (choosenConfigCount[0] == 0)
					throw new InvalidOperationException("unable to find basic visual");

				visual = Glx.GetVisualFromFBConfig(display, *choosenConfig);
				Glx.XFree((IntPtr)choosenConfig);
			}

			Glx.XVisualInfo info = (Glx.XVisualInfo)Marshal.PtrToStructure(visual, typeof(Glx.XVisualInfo));

			// Create direct context
			rContext = Glx.CreateContext(display, info, IntPtr.Zero, true);
			if (rContext == IntPtr.Zero) {
				// Fallback to not direct context
				rContext = Glx.CreateContext(display, info, IntPtr.Zero, false);
			}

			if (rContext == IntPtr.Zero)
				throw new InvalidOperationException("unable to create context");


			XServerDeviceContext x11DeviceCtx = new XServerDeviceContext();

			x11DeviceCtx.Display = display;
			x11DeviceCtx.Screen = screen;
			x11DeviceCtx.WindowHandle = window.Handle;

			rDevice = x11DeviceCtx;

			return (rContext);
		}

		/// <summary>
		/// Force execution of static constructor.
		/// </summary>
		internal static void Touch() { sRenderCaps.GetHashCode(); }

		/// <summary>
		/// RenderContext constructor.
		/// </summary>
		/// <exception cref="InvalidOperationException">
		/// This exception is throw in the case it's not possible to create a valid OpenGL context.
		/// </exception>
		public RenderContext()
		{
			IDeviceContext deviceContext = DeviceContextFactory.Create(HiddenWindow);

			// Release device context on dispose
			mCommonDeviceContext = true;
			// Create render context
			CreateRenderContext(deviceContext, null, GLVersion.Current);
		}

		/// <summary>
		/// RenderContext constructor.
		/// </summary>
		/// <param name="deviceContext">
		/// A <see cref="IDeviceContext"/> that specifies the device context which has to be linked this
		/// this Render context.
		/// </param>
		/// <exception cref="InvalidOperationException">
		/// This exception is throw in the case it's not possible to create a valid OpenGL context.
		/// </exception>
		public RenderContext(IDeviceContext deviceContext)
		{
			// Create render context
			CreateRenderContext(deviceContext, null, GLVersion.Current);
		}

		/// <summary>
		/// Construct a RenderContext implementing the current OpenGL version.
		/// </summary>
		/// <param name="hSharedContext">
		/// A <see cref="RenderContext"/> that specifies the render context which has to be linked this this Render context (to share resource with it).
		/// In the case this parameter is null, this is equivalent to <see cref="Derm.Render.RenderContext.ctor"/>
		/// </param>
		/// <exception cref="InvalidOperationException">
		/// This exception is throw in the case it's not possible to create a valid OpenGL context.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown if <paramref name="hSharedContext"/> is not null and it was created by a thread different from the calling one.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown if <paramref name="hSharedContext"/> is not null and it is disposed.
		/// </exception>
		public RenderContext(RenderContext hSharedContext)
		{
			IDeviceContext deviceContext = DeviceContextFactory.Create(HiddenWindow);

			// Release device context on dispose
			mCommonDeviceContext = true;
			// Create render context
			CreateRenderContext(deviceContext, hSharedContext, GLVersion.Current);
		}

		/// <summary>
		/// Construct a RenderContext implementing the current OpenGL version.
		/// </summary>
		/// <param name="deviceContext">
		/// A <see cref="IDeviceContext"/> that specifies the device context which has to be linked this
		/// this Render context.
		/// </param>
		/// <param name="hSharedContext">
		/// A <see cref="RenderContext"/> that specifies the render context which has to be linked this
		/// this Render context (to share resource with it).
		/// </param>
		/// <exception cref="ArgumentException">
		/// This exception is thrown if <paramref name="hSharedContext"/> is not null and it was created by a thread different from the calling one.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown if <paramref name="hSharedContext"/> is not null and it is disposed.
		/// </exception>
		public RenderContext(IDeviceContext deviceContext, RenderContext hSharedContext)
		{
			// Create render context
			CreateRenderContext(deviceContext, hSharedContext, GLVersion.Current);
		}

		/// <summary>
		/// Construct a RenderContext specifying the implemented OpenGL version.
		/// </summary>
		/// <param name="version">
		/// A <see cref="GLVersion"/> that specifies the minimum OpenGL version required to implement.
		/// </param>
		/// <param name="hSharedContext">
		/// A <see cref="RenderContext"/> that specifies the render context which has to be linked this
		/// this Render context (to share resource with it).
		/// </param>
		/// <exception cref="ArgumentException">
		/// Exception thrown in the case <paramref name="version"/> is different from the currently implemented by the derive,
		/// and the OpenGL extension WGL_ARB_create_context_profile or WGL_ARB_create_context are not implemented.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown in the case <paramref name="version"/> specifies a forward compatible version (greater than or equal to
		/// <see cref="GLVersion.Version_3_2"/>), and the OpenGL extension WGL_ARB_create_context_profile or WGL_ARB_create_context
		/// are not implemented.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown in the case <paramref name="devctx"/> is <see cref="System.IntPtr.Zero"/>.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// This exception is throw in the case it's not possible to create a valid OpenGL context.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown if <paramref name="hSharedContext"/> is not null and it was created by a thread different from the calling one.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown if <paramref name="hSharedContext"/> is not null and it is disposed.
		/// </exception>
		public RenderContext(GLVersion version, RenderContext hSharedContext)
		{
			IDeviceContext deviceContext = DeviceContextFactory.Create(HiddenWindow);

			// Release device context on dispose
			mCommonDeviceContext = true;
			// Create render context
			CreateRenderContext(deviceContext, hSharedContext, version);
		}

		/// <summary>
		/// Construct a RenderContext specifying the implemented OpenGL version.
		/// </summary>
		/// <param name="version">
		/// A <see cref="GLVersion"/> that specifies the minimum OpenGL version required to implement.
		/// </param>
		/// <param name="deviceContext">
		/// A <see cref="IDeviceContext"/> that specifies the device context which has to be linked this
		/// this Render context.
		/// </param>
		/// <param name="hSharedContext">
		/// A <see cref="RenderContext"/> that specifies the render context which has to be linked this
		/// this Render context (to share resource with it).
		/// </param>
		/// <exception cref="ArgumentException">
		/// Exception thrown in the case <paramref name="version"/> is different from the currently implemented by the derive,
		/// and the OpenGL extension WGL_ARB_create_context_profile or WGL_ARB_create_context are not implemented.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown in the case <paramref name="version"/> specifies a forward compatible version (greater than or equal to
		/// <see cref="GLVersion.Version_3_2"/>), and the OpenGL extension WGL_ARB_create_context_profile or WGL_ARB_create_context
		/// are not implemented.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown in the case <paramref name="devctx"/> is <see cref="System.IntPtr.Zero"/>.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// This exception is thrown in the case it's not possible to create a valid OpenGL context.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown if <paramref name="hSharedContext"/> is not null and it was created by a thread different from the calling one.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown if <paramref name="hSharedContext"/> is not null and it is disposed.
		/// </exception>
		public RenderContext(GLVersion version, IDeviceContext deviceContext, RenderContext hSharedContext)
		{
			// Create render context
			CreateRenderContext(deviceContext, hSharedContext, version);
		}

		/// <summary>
		/// Create a RenderContext specifying the implemented OpenGL version and a shared object space.
		/// </summary>
		/// <param name="deviceContext">
		/// A <see cref="IDeviceContext"/> that specifies the device context which has to be linked this this Render context.
		/// </param>
		/// <param name="hSharedContext">
		/// A <see cref="RenderContext"/> that specifies the render context which has to be linked this
		/// this Render context (to share resource with it).
		/// </param>
		/// <param name="version">
		/// A <see cref="GLVersion"/> that specifies the minimum OpenGL version required to implement.
		/// </param>
		/// <exception cref="ArgumentException">
		/// This exception is thrown in the case <paramref name="devctx"/> is <see cref="System.IntPtr.Zero"/>.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown if <paramref name="hSharedContext"/> is not null and it is disposed.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown if <paramref name="hSharedContext"/> is not null and it was created by a thread different from the calling one.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// This exception is thrown in the case <paramref name="version"/> specifies a forward compatible version (greater than or equal to
		/// <see cref="GLVersion.Version_3_2"/>), and the OpenGL extension WGL_ARB_create_context_profile or WGL_ARB_create_context
		/// are not implemented.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// Exception thrown in the case <paramref name="version"/> is different from the currently implemented by the driver,
		/// and the OpenGL extension WGL_ARB_create_context_profile or WGL_ARB_create_context are not implemented.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// This exception is thrown in the case it's not possible to create a valid OpenGL context.
		/// </exception>
		private void CreateRenderContext(IDeviceContext deviceContext, RenderContext hSharedContext, GLVersion version)
		{
			try {
				IntPtr pSharedContext = (hSharedContext != null) ? hSharedContext.mRenderContext : IntPtr.Zero;

#if DEBUG
				mConstructorStackTrace = Environment.StackTrace;
#endif

				// Defaulting OpenGL version
				if (version == GLVersion.Current)
					version = sCurrentGLVersion;

				sLog.Debug("Create render context (Version: {0}, Sharing: {1})", version, hSharedContext != null ? hSharedContext.ObjectNameSpace.ToString() : "none");

				// Store thread ID of the render context
				mRenderContextThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
				// Store thread ID of the device context
				mDeviceContextThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;

				if (deviceContext == null)
					throw new ArgumentNullException("devctx");
				if ((hSharedContext != null) && (hSharedContext.mDeviceContext == null))
					throw new ArgumentException("shared context disposed", "hSharedContext");
				if ((hSharedContext != null) && (hSharedContext.mRenderContextThreadId != mRenderContextThreadId))
					throw new ArgumentException("shared context created from another thread", "hSharedContext");
				if ((version != sCurrentGLVersion) && ((CurrentCaps.CreateContext.Supported == false) && (CurrentCaps.CreateContextProfile.Supported == false)))
					throw new ArgumentException("unable to specify OpenGL version when GL_ARB_create_context[_profile] is not supported");
				if ((sVersionDb[version].ForwardCompatible == true) && ((CurrentCaps.CreateContext.Supported == false) && (CurrentCaps.CreateContextProfile.Supported == false)))
					throw new ArgumentException("unable to specify forward-compatible OpenGL version when GL_ARB_create_context[_profile] is not supported");

				// Store device context handle
				mDeviceContext = deviceContext;

				//if (CurrentCaps.CreateContext.Supported || CurrentCaps.CreateContextProfile.Supported && false) {
				if (false) {
					List<int> cAttributes = new List<int>();
					int rContextProfileBits = 0;
					int rContextFlags = 0;

					// Requires a specific version
					Debug.Assert(Wgl.CONTEXT_MAJOR_VERSION_ARB == Glx.CONTEXT_MAJOR_VERSION_ARB);
					Debug.Assert(Wgl.CONTEXT_MINOR_VERSION_ARB == Glx.CONTEXT_MINOR_VERSION_ARB);
					cAttributes.AddRange(new int[] {
						Wgl.CONTEXT_MAJOR_VERSION_ARB, sVersionDb[version].GLMajor,
						Wgl.CONTEXT_MINOR_VERSION_ARB, sVersionDb[version].GLMinor
					});

					if (version >= GLVersion.Version_3_2) {
						if (sVersionDb[version].ForwardCompatible == true) {
							Debug.Assert(Wgl.CONTEXT_FORWARD_COMPATIBLE_BIT_ARB == Glx.CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);

							// Profile mask (ignored if requesting a < 3.2 context)
							rContextProfileBits |= (int)(Wgl.CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);

							// Context flags: forward compatibility
							rContextFlags |= (int)(Wgl.CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);
						} else {
							Debug.Assert(Wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB == Glx.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);

							// Profile mask (ignored if requesting a < 3.2 context)
							rContextProfileBits |= (int)(Wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
						}
#if DEBUG
						// Context flags: debug
						rContextFlags |= (int)(Wgl.CONTEXT_DEBUG_BIT_ARB);
#endif
						// Profile and flags
						Debug.Assert(Wgl.CONTEXT_PROFILE_MASK_ARB == Glx.CONTEXT_PROFILE_MASK_ARB);
						Debug.Assert(Wgl.CONTEXT_FLAGS_ARB == Glx.CONTEXT_FLAGS_ARB);
						cAttributes.AddRange(new int[] {
							Wgl.CONTEXT_PROFILE_MASK_ARB, rContextProfileBits,
							Wgl.CONTEXT_FLAGS_ARB, rContextFlags
						});
					}
					// End of attributes
					cAttributes.Add(0);

					// Create rendering context
					if ((mRenderContext = Gl.CreateContextAttrib(mDeviceContext, pSharedContext, cAttributes.ToArray())) == IntPtr.Zero) {
						int err = Gl.GetError();

						switch (err) {
							case Gl.INVALID_OPERATION:
								throw new InvalidOperationException(String.Format("unable to create context {0}.{1} ({2})", sVersionDb[version].GLMajor, sVersionDb[version].GLMinor, "invalid operation"));
							case Wgl.ERROR_INVALID_VERSION_ARB:
								throw new InvalidOperationException(String.Format("unable to create context {0}.{1} ({2})", sVersionDb[version].GLMajor, sVersionDb[version].GLMinor, "invalid version"));
							case Wgl.ERROR_INVALID_PROFILE_ARB:
								throw new InvalidOperationException(String.Format("unable to create context {0}.{1} ({2})", sVersionDb[version].GLMajor, sVersionDb[version].GLMinor, "invalid profile"));
							case Wgl.ERROR_INVALID_PIXEL_TYPE_ARB:
								throw new InvalidOperationException(String.Format("unable to create context {0}.{1} ({2})", sVersionDb[version].GLMajor, sVersionDb[version].GLMinor, "invalid pixel format"));
							default:
								throw new InvalidOperationException(String.Format("unable to create context {0}.{1} ({2})", sVersionDb[version].GLMajor, sVersionDb[version].GLMinor, "unknown error " + err));
						}
					}
				} else {
					// Create rendering context
					if ((mRenderContext = Gl.CreateContext(mDeviceContext)) == IntPtr.Zero)
						throw new InvalidOperationException("unable to create context " + sVersionDb[version].GLMajor + "." + sVersionDb[version].GLMinor);
					// Shader lists between context
					if (pSharedContext != IntPtr.Zero) {
						if (Wgl.ShareLists(mRenderContext, pSharedContext) == false)
							throw new InvalidOperationException("failed to share object name space");
					}
				}

				RenderContext rContextCurrent = GetCurrentContext();		// Back current context, if any
				IDeviceContext rContextCurrentDevice = (rContextCurrent != null) ? rContextCurrent.mCurrentDeviceContext : null;

				// This will cause OpenGL operation flushed... not too bad
				MakeCurrent(deviceContext, true);

				// Get the current OpenGL implementation supported by this RenderContext
				mVersion = ParseGLVersion(Gl.GetString(Gl.VERSION));
				// Get the current OpenGL Shading Language implementation supported by this RenderContext
				mShadingVersion = ParseGLSLVersion(Gl.GetString(Gl.SHADING_LANGUAGE_VERSION));
				// Determine the compatibility profile
				mCompatibilityProfile = (version < GLVersion.Version_3_1) && (mVersion >= GLVersion.Version_3_1);

				sLog.Debug("\tActual OpenGL implementation: {0}", mVersion);
				sLog.Debug("\tActual OpenGL Shading Language implementation: {0}", mShadingVersion);
				sLog.Debug("\tCompatility profile: {0}", mCompatibilityProfile);

				// Cache context capabilities for this version
				if (sRenderCapsDb.ContainsKey(mVersion) == false)
					sRenderCapsDb[mVersion] = QueryOpenGLInfo(deviceContext, this);

				// Collect the default render state vector
				mRenderStateSetStack.AddLast(RenderStateSet.GetDefaultSet());

				// Determine this RenderContext object name space and garbage service
				if (hSharedContext != null) {
					// Sharing same object name space
					mObjectNameSpace = hSharedContext.mObjectNameSpace;
					// Garbage service is the same (object name space is shared)
					mGarbageService = hSharedContext.mGarbageService;
					// Shader cache service is the same (object name space is shared)
					mShaderCacheService = hSharedContext.mShaderCacheService;

					// Test for effective sharing
					TestSharingObjects(hSharedContext);
				} else {
					// Reserved object name space
					mObjectNameSpace = Guid.NewGuid();
					// Reserved garbage service
					mGarbageService = new RenderGarbageService();
					// Reserved shader cache service
					mShaderCacheService = new ShaderCacheService();

					// Effective sharing false by default
				}
				// Bind this garbage service (also reference it since potentially shared across contextes)
				mGarbageService.BindObjectNameSpace(this);
				if (mShaderCacheService != null)
					mShaderCacheService.BindObjectNameSpace(this);

				// Restore previous current context, if any
				if (rContextCurrent != null)
					rContextCurrent.MakeCurrent(rContextCurrentDevice, true);
				else
					MakeCurrent(deviceContext, false);
			} catch {
				// Make sure all resource are released
				Dispose(true);
				// Rethrow the exception
				throw;
			}
		}

#if DEBUG
		/// <summary>
		/// Stack trace when constructor were called.
		/// </summary>
		private string mConstructorStackTrace = String.Empty;
#endif
		
		#endregion

		#region OpenGL Versioning

		/// <summary>
		/// Supported OpenGL implementations.
		/// </summary>
		public enum GLVersion
		{
			/// <summary>
			/// OpenGL 1.0.
			/// </summary>
			Version_1_0 = 0,
			/// <summary>
			/// OpenGL 1.1.
			/// </summary>
			Version_1_1,
			/// <summary>
			/// OpenGL 1.2.
			/// </summary>
			Version_1_2,
			/// <summary>
			/// OpenGL 1.2.1.
			/// </summary>
			Version_1_2_1,
			/// <summary>
			/// OpenGL 1.3.
			/// </summary>
			Version_1_3,
			/// <summary>
			/// OpenGL 1.1.
			/// </summary>
			Version_1_4,
			/// <summary>
			/// OpenGL 1.5.
			/// </summary>
			Version_1_5,

			/// <summary>
			/// OpenGL 2.0.
			/// </summary>
			Version_2_0,
			/// <summary>
			/// OpenGL 2.1.
			/// </summary>
			Version_2_1,

			/// <summary>
			/// OpenGL 3.0.
			/// </summary>
			Version_3_0,
			/// <summary>
			/// OpenGL 3.1.
			/// </summary>
			Version_3_1,
			/// <summary>
			/// OpenGL 3.2.
			/// </summary>
			Version_3_2,
			/// <summary>
			/// OpenGL 3.3.
			/// </summary>
			Version_3_3,

			/// <summary>
			/// Current OpenGL implementation.
			/// </summary>
			Current
		}

		/// <summary>
		/// Supported OpenGL Shading Language implementations.
		/// </summary>
		public enum GLSLVersion
		{
			/// <summary>
			/// No OpenGL Shading Language implementation
			/// </summary>
			None = 0,
			/// <summary>
			/// OpenGL Shading Language 1.1.0.
			/// </summary>
			Version_1_1 = 110,
			/// <summary>
			/// OpenGL Shading Language 1.2.0.
			/// </summary>
			Version_1_2 = 120,
			/// <summary>
			/// OpenGL Shading Language 1.3.0.
			/// </summary>
			Version_1_3 = 130,
			/// <summary>
			/// OpenGL Shading Language 1.4.0.
			/// </summary>
			Version_1_4 = 140,
			/// <summary>
			/// OpenGL Shading Language 1.5.0.
			/// </summary>
			Version_1_5 = 150,
			/// <summary>
			/// Current OpenGL Shading Language implementation.
			/// </summary>
			Current = 65536,
		}

		/// <summary>
		/// The OpenGL version implemented by this RenderContext.
		/// </summary>
		public GLVersion Version { get { return (mVersion); } }

		/// <summary>
		/// The OpenGL Shading Language version implemented by this RenderContext.
		/// </summary>
		public GLSLVersion ShadingVersion { get { return (mShadingVersion); } }

		/// <summary>
		/// The compatibility profile presence implemented by this RenderContext.
		/// </summary>
		public bool CompatibilityProfile { get { return (mCompatibilityProfile); } }

		/// <summary>
		/// The OpenGL version implemented by this RenderContext.
		/// </summary>
		private GLVersion mVersion = GLVersion.Current;

		/// <summary>
		/// The OpenGL Shading Language version implemented by this RenderContext.
		/// </summary>
		private GLSLVersion mShadingVersion = GLSLVersion.Current;

		/// <summary>
		/// Compatibility profile enabled (only for versions greater than OpenGL 3.0).
		/// </summary>
		private bool mCompatibilityProfile = false;

		#region Version Database & Utilities

		/// <summary>
		/// Get the number representation of a <see cref="GLVersion"/>.
		/// </summary>
		/// <param name="version">
		/// A <see cref="GLVersion"/> which has to be represented by an integer.
		/// </param>
		/// <returns>
		/// It returns a <see cref="System.Int32"/> representing <paramref name="version"/>.
		/// </returns>
		internal static int GetGLVersionId(GLVersion version)
		{
			return (sVersionDb[version].GLVersionID);
		}

		/// <summary>
		/// Get the number representation of a <see cref="GLSLVersion"/>.
		/// </summary>
		/// <param name="version">
		/// A <see cref="GLSLVersion"/> which has to be represented by an integer.
		/// </param>
		/// <returns>
		/// It returns a <see cref="System.Int32"/> representing <paramref name="version"/>.
		/// </returns>
		internal static int GetGLSLVersionId(GLSLVersion version)
		{
			return (sShadingVersionDb[version].GLSLVersionID);
		}

		/// <summary>
		/// OpenGL standard implementation.
		/// </summary>
		internal struct GLVersionDescr
		{
			/// <summary>
			/// Major version for this OpenGL version.
			/// </summary>
			public int GLMajor { get { return (GLVersionID / 100); } }

			/// <summary>
			/// Minor version for this OpenGL version.
			/// </summary>
			public int GLMinor { get { return ((GLVersionID % 100) / 10); } }

			/// <summary>
			/// OpenGL version.
			/// </summary>
			public GLVersion GLVersion;
			/// <summary>
			/// OpenGL version identifier.
			/// </summary>
			public int GLVersionID;
			/// <summary>
			/// OpenGL Shading Language version.
			/// </summary>
			public GLSLVersion GLSLVersion;
			/// <summary>
			/// OpenGL Shading Language version identifier.
			/// </summary>
			public int GLSLVersionID;
			/// <summary>
			/// Implementation forward compatibility flag.
			/// </summary>
			public bool ForwardCompatible { get { return (GLVersion >= RenderContext.GLVersion.Version_3_0); } }
		}

		/// <summary>
		/// OpenGL version currently implemented.
		/// </summary>
		/// <remarks>
		/// Higher OpenGL versions versions cannot be requested to be implemented.
		/// </remarks>
		internal static GLVersion sCurrentGLVersion;

		/// <summary>
		/// OpenGL Shading Language version currently implemented.
		/// </summary>
		/// <remarks>
		/// Higher OpenGL Shading Language versions cannot be requested to be implemented.
		/// </remarks>
		internal static GLSLVersion sCurrentShadingGLVersion;

		/// <summary>
		/// Register supported OpenGL versions.
		/// </summary>
		private static void RegisterSupportedOpenGLVersions()
		{
			GLVersionDescr glVersionItem;

			// OpenGL 1.0
			glVersionItem.GLVersion = GLVersion.Version_1_0;
			glVersionItem.GLVersionID = 100;
			glVersionItem.GLSLVersion = GLSLVersion.None;
			glVersionItem.GLSLVersionID = 0;
			sVersionDb[GLVersion.Version_1_0] = glVersionItem;
			// OpenGL 1.1
			glVersionItem.GLVersion = GLVersion.Version_1_1;
			glVersionItem.GLVersionID = 110;
			glVersionItem.GLSLVersion = GLSLVersion.None;
			glVersionItem.GLSLVersionID = 0;
			sVersionDb[GLVersion.Version_1_1] = glVersionItem;
			// OpenGL 1.2
			glVersionItem.GLVersion = GLVersion.Version_1_2;
			glVersionItem.GLVersionID = 120;
			glVersionItem.GLSLVersion = GLSLVersion.None;
			glVersionItem.GLSLVersionID = 0;
			sVersionDb[GLVersion.Version_1_2] = glVersionItem;
			// OpenGL 1.2.1
			glVersionItem.GLVersion = GLVersion.Version_1_2_1;
			glVersionItem.GLVersionID = 121;
			glVersionItem.GLSLVersion = GLSLVersion.None;
			glVersionItem.GLSLVersionID = 0;
			sVersionDb[GLVersion.Version_1_2_1] = glVersionItem;
			// OpenGL 1.3
			glVersionItem.GLVersion = GLVersion.Version_1_3;
			glVersionItem.GLVersionID = 130;
			glVersionItem.GLSLVersion = GLSLVersion.None;
			glVersionItem.GLSLVersionID = 0;
			sVersionDb[GLVersion.Version_1_3] = glVersionItem;
			// OpenGL 1.4
			glVersionItem.GLVersion = GLVersion.Version_1_4;
			glVersionItem.GLVersionID = 140;
			glVersionItem.GLSLVersion = GLSLVersion.None;
			glVersionItem.GLSLVersionID = 0;
			sVersionDb[GLVersion.Version_1_4] = glVersionItem;
			// OpenGL 1.5
			glVersionItem.GLVersion = GLVersion.Version_1_5;
			glVersionItem.GLVersionID = 150;
			glVersionItem.GLSLVersion = GLSLVersion.None;
			glVersionItem.GLSLVersionID = 0;
			sVersionDb[GLVersion.Version_1_5] = glVersionItem;

			// OpenGL 2.0
			glVersionItem.GLVersion = GLVersion.Version_2_0;
			glVersionItem.GLVersionID = 200;
			glVersionItem.GLSLVersion = GLSLVersion.Version_1_2;
			glVersionItem.GLSLVersionID = 120;
			sVersionDb[GLVersion.Version_2_0] = glVersionItem;
			sShadingVersionDb[GLSLVersion.Version_1_2] = glVersionItem;
			// OpenGL 2.1
			glVersionItem.GLVersion = GLVersion.Version_2_1;
			glVersionItem.GLVersionID = 210;
			glVersionItem.GLSLVersion = GLSLVersion.Version_1_2;
			glVersionItem.GLSLVersionID = 120;
			sVersionDb[GLVersion.Version_2_1] = glVersionItem;
			sShadingVersionDb[GLSLVersion.Version_1_2] = glVersionItem;

			// OpenGL 3.0
			glVersionItem.GLVersion = GLVersion.Version_3_0;
			glVersionItem.GLVersionID = 300;
			glVersionItem.GLSLVersion = GLSLVersion.Version_1_3;
			glVersionItem.GLSLVersionID = 130;
			sVersionDb[GLVersion.Version_3_0] = glVersionItem;
			sShadingVersionDb[GLSLVersion.Version_1_3] = glVersionItem;
			// OpenGL 3.1
			glVersionItem.GLVersion = GLVersion.Version_3_1;
			glVersionItem.GLVersionID = 310;
			glVersionItem.GLSLVersion = GLSLVersion.Version_1_4;
			glVersionItem.GLSLVersionID = 140;
			sVersionDb[GLVersion.Version_3_1] = glVersionItem;
			sShadingVersionDb[GLSLVersion.Version_1_4] = glVersionItem;
			// OpenGL 3.2
			glVersionItem.GLVersion = GLVersion.Version_3_2;
			glVersionItem.GLVersionID = 320;
			glVersionItem.GLSLVersion = GLSLVersion.Version_1_5;
			glVersionItem.GLSLVersionID = 150;
			sVersionDb[GLVersion.Version_3_2] = glVersionItem;
			sShadingVersionDb[GLSLVersion.Version_1_5] = glVersionItem;
			// OpenGL 3.3
			glVersionItem.GLVersion = GLVersion.Version_3_3;
			glVersionItem.GLVersionID = 330;
			glVersionItem.GLSLVersion = GLSLVersion.Version_1_5;
			glVersionItem.GLSLVersionID = 150;
			sVersionDb[GLVersion.Version_3_3] = glVersionItem;
			sShadingVersionDb[GLSLVersion.Version_1_5] = glVersionItem;
		}

		/// <summary>
		/// Parse OpenGL version string.
		/// </summary>
		private static GLVersion ParseGLVersion(string glVersionString)
		{
			GLVersion version = GLVersion.Version_1_0;
			string[] vTokens;
			int major, minor, rev = 0, glVersion;

			if (glVersionString == null)
				throw new ArgumentNullException("glVersionString");

			// Parse OpenGL version string
			vTokens = glVersionString.Split('.', ' ');
			if (vTokens.Length < 2)
				throw new ArgumentException("unable to determine OpenGL version from string " + glVersionString);
			major = Int32.Parse(vTokens[0], NumberFormatInfo.InvariantInfo);
			minor = Int32.Parse(vTokens[1], NumberFormatInfo.InvariantInfo);
			if (vTokens.Length >= 3)
				rev = Int32.Parse(vTokens[2], NumberFormatInfo.InvariantInfo);

			// Compose ID corresponding to this version
			glVersion = major * 100 + minor * 10 +rev;

			// Get the highest OpenGL version desciption
			foreach (GLVersionDescr vDescr in sVersionDb.Values) {
				if (vDescr.GLVersionID <= glVersion)
					version = vDescr.GLVersion;
			}

			return (version);
		}

		/// <summary>
		/// Parse OpenGL version string.
		/// </summary>
		private static GLSLVersion ParseGLSLVersion(string glslVersionString)
		{
			GLSLVersion version = GLSLVersion.None;
			Match versionMatch;
			string[] vTokens;
			int major, minor, glslVersion;

			if (glslVersionString == null)
				throw new ArgumentNullException("glVersionString");

			versionMatch = sGlslVersionRegex.Match(glslVersionString);

			if (versionMatch.Success == false)
				throw new ArgumentException(String.Format("version '{0}' not recognized", glslVersionString), "glslVersionString");

			// Parse OpenGL Shading Language version string
			major = Int32.Parse(versionMatch.Groups["Major"].Value, NumberFormatInfo.InvariantInfo);
			minor = Int32.Parse(versionMatch.Groups["Minor"].Value, NumberFormatInfo.InvariantInfo);

			// Cover version paterns like 1.20
			if (minor >= 10) minor /= 10;

			// Compose ID corresponding to this version
			glslVersion = major * 100 + minor * 10;
			
			// Get the highest OpenGL SL version desciption
			foreach (GLVersionDescr vDescr in sVersionDb.Values) {
				if ((int)vDescr.GLSLVersionID <= glslVersion) {
					version = vDescr.GLSLVersion;
				}
			}

			return (version);
		}

		/// <summary>
		/// Supported OpenGL implementations (indexed by OpenGL version).
		/// </summary>
		private static readonly Dictionary<GLVersion, GLVersionDescr> sVersionDb = new Dictionary<GLVersion, GLVersionDescr>();

		/// <summary>
		/// Supported OpenGL implementations (indexed by OpenGL Shading Language version, the default one).
		/// </summary>
		/// <remarks>
		/// Other implementation could implement lower OpenGL Shading Language version respect the default supported by
		/// the current OpenGL version.
		/// </remarks>
		private static readonly Dictionary<GLSLVersion, GLVersionDescr> sShadingVersionDb = new Dictionary<GLSLVersion, GLVersionDescr>();

		/// <summary>
		/// Regular expression for parsing OpenGL version string.
		/// </summary>
		private static Regex sGlVersionRegex = new Regex(@"^(?<Major>\d)\.(?<Minor>\d)(\.(?<Rev>\d))?");

		/// <summary>
		/// Regular expression for parsing OpenGL Shading Language version string.
		/// </summary>/
		private static Regex sGlslVersionRegex = new Regex(@"^(?<Major>\d)\.(?<Minor>\d{1,}).*");

		#endregion

		#endregion

		#region OpenGL Extension Support

		#region Query OpenGL Extensions and Limits Attributes

		/// <summary>
		/// Base class for managing extension offered by the OpenGL platform.
		/// </summary>
		private class ExtensionAttribute : Attribute
		{
			/// <summary>
			/// Construct a RequiredExtensionAttribute.
			/// </summary>
			/// <param name="extString">
			/// A <see cref="System.String"/> that specifies the main extension name string.
			/// </param>
			/// <param name="altStrings">
			/// A <see cref="T:System.String[]"/> that specifies the alternative extension name strings.
			/// </param>
			public ExtensionAttribute(string extString, params string[] altStrings)
			{
				if (String.IsNullOrEmpty(extString))
					throw new ArgumentException("invalid extension string", "extString");

				// Store main extention string
				mExtensionString = extString;
				// Store alternative extension strings
				mAlternativeExtensionStrings = altStrings;
			}

			/// <summary>
			/// Check whether one of the extention strings is supported.
			/// </summary>
			/// <param name="ctx">
			/// A <see cref="RenderContext"/> that specifies the current OpenGL version to test for extension support. In the case this
			/// parameter is null, the test fallback to the current OpenGL version.
			/// </param>
			public bool IsSupported(RenderContext ctx, IDeviceContext deviceContext)
			{
				if (IsSupportedExtension(ctx, deviceContext, mExtensionString) == true)
					return (true);
				if (mAlternativeExtensionStrings != null) {
					foreach (string ext in mAlternativeExtensionStrings)
						if (IsSupportedExtension(ctx, deviceContext, ext) == true)
							return (true);
				}

				return (false);
			}

			/// <summary>
			/// Determine whether an OpenGL extension is supported by a <see cref="RenderContext"/>.
			/// </summary>
			/// <param name="ctx">
			/// A <see cref="RenderContext"/> that specifies the current OpenGL version to test for extension support. In the case this
			/// parameter is null, the test fallback to the current OpenGL version.
			/// </param>
			/// <param name="ext">
			/// A <see cref="System.String"/> that specifies the OpenGL extension for support.
			/// </param>
			/// <returns>
			/// It returns a boolean value indicating whether the OpenGL extension is supported by a specific OpenGL version.
			/// </returns>
			private bool IsSupportedExtension(RenderContext ctx, IDeviceContext deviceContext, string ext)
			{
				if (ext.StartsWith("GL_")) {
					if (ctx == null)
						return (Gl.HasExtension(ext));
					else
						return (Gl.HasExtension(RenderContext.GetGLVersionId(ctx.Version), ext));
				} else if (ext.StartsWith("GLX_")) {
					switch (Environment.OSVersion.Platform) {
						case PlatformID.Unix:
							return (Glx.HasExtension(deviceContext, ext));
						default:
							return (false);
					}
				} else if (ext.StartsWith("WGL_")) {
					switch (Environment.OSVersion.Platform) {
						case PlatformID.Win32Windows:
						case PlatformID.Win32NT:
						case PlatformID.WinCE:
							return (Wgl.HasExtension(deviceContext, ext));
						default:
							return (false);
					}
				} else
					throw new ArgumentException(ext + "is not a recognized GL extension", "ext");
			}

			/// <summary>
			/// Main extension string.
			/// </summary>
			private string mExtensionString;

			/// <summary>
			/// Alternative extension strings.
			/// </summary>
			private string[] mAlternativeExtensionStrings;
		}

		/// <summary>
		/// Attribute indicating which OpenGL extension string is required for supporting a framework feature.
		/// </summary>
		/// <remarks>
		/// 
		/// </remarks>
		[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
		private class RequiredExtensionAttribute : ExtensionAttribute
		{
			/// <summary>
			/// Construct a RequiredExtensionAttribute.
			/// </summary>
			/// <param name="extString">
			/// A <see cref="System.String"/> that specifies the main extension name string.
			/// </param>
			/// <param name="altStrings">
			/// A <see cref="T:System.String[]"/> that specifies the alternative extension name strings.
			/// </param>
			public RequiredExtensionAttribute(string extString, params string[] altStrings) : base(extString, altStrings)
			{
				
			}
		}

		/// <summary>
		/// Attribute indicating which OpenGL extension string is sufficient for supporting a framework feature.
		/// </summary>
		[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
		private class SubsetExtensionAttribute : ExtensionAttribute
		{
			/// <summary>
			/// Construct a SubsetExtensionAttribute.
			/// </summary>
			/// <param name="extString">
			/// A <see cref="System.String"/> that specifies the main extension name string.
			/// </param>
			/// <param name="altStrings">
			/// A <see cref="T:System.String[]"/> that specifies the alternative extension name strings.
			/// </param>
			public SubsetExtensionAttribute(string extString, params string[] altStrings) : base(extString, altStrings)
			{
				
			}
		}

		/// <summary>
		/// Attribute indicating which OpenGL version is sufficient to support the underlying OpenGL extension.
		/// </summary>
		/// <remarks>
		/// <para>
		/// If this attribute is set, specify that the extension support boolean field is checked only if the current
		/// renderer support the OpenGL version specified as argument in constructor.
		/// </para>
		/// <para>
		/// Often, this is indicated on OpenGL extension specification, in two forms.
		/// 
		/// The first one it's in the form "The extension is written against the OpenGL X.X[.X] Specification". In this case
		/// that version shall be taken by reference.
		/// 
		/// The previous form can be overriden by a more explicit form: "OpenGL X.X[.X] is required." In this case the minimum
		/// version is the required one. Supposedly, it means that the specification is written starting from the current specification
		/// at write time, but it is valid from the OpenGL version X.X[.X].
		/// </para>
		/// </remarks>
		[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
		private class MinVersionExtensionAttribute : Attribute
		{
			/// <summary>
			/// Construct a MinVersionExtensionAttribute specifying the OpenGL version.
			/// </summary>
			/// <param name="version">
			/// A <see cref="GLVersion"/> that specify the minimum version that support an OpenGL extension.
			/// </param>
			public MinVersionExtensionAttribute(GLVersion version) : this(version, null)
			{

			}

			/// <summary>
			/// Construct a MinVersionExtensionAttribute specifying the OpenGL version.
			/// </summary>
			/// <param name="version">
			/// A <see cref="GLVersion"/> that specify the minimum version that support an OpenGL extension.
			/// </param>
			/// <param name="reqExts">
			/// A <see cref="System.String"/> that specifies an OpenGL extension name which will be evaluated for support
			/// in the case the current implementation is lower than <paramref name="version"/>. In the case this named
			/// extension is supported, also the annotated extension could be supported.
			/// </param>
			public MinVersionExtensionAttribute(GLVersion version, string reqExts)
			{
				// Store version
				mVersion = version;
				// Store alternative extension
				if (reqExts != null)
					mExtAlternative = new ExtensionAttribute(reqExts);
			}

			/// <summary>
			/// Minimum requirement to support an OpenGL extension are supported.
			/// </summary>
			/// <param name="ctx">
			/// A <see cref="RenderContext"/> used for testing OpenGL extension support.
			/// </param>
			/// <exception cref="ArgumentNullException">
			/// Exception thrown in the case <paramref name="ctx"/> is null.
			/// </exception>
			public bool IsSupported(RenderContext ctx, IDeviceContext deviceContext)
			{
				if (ctx == null)
					return ((sCurrentGLVersion >= mVersion) || ((mExtAlternative != null) && (mExtAlternative.IsSupported(ctx, deviceContext) == true)));
				return ((ctx.Version >= mVersion) || ((mExtAlternative != null) && (mExtAlternative.IsSupported(ctx, deviceContext) == true)));
			}

			/// <summary>
			/// Minimum OpenGL version to support an OpenGL extension.
			/// </summary>
			public GLVersion MinVersion { get { return (mVersion); } }

			/// <summary>
			/// Minimum OpenGL version to support an OpenGL extension.
			/// </summary>
			private readonly GLVersion mVersion;

			/// <summary>
			/// Extension to be tested for possible support in the case current implementation is lower than <see cref="mVersion"/>.
			/// </summary>
			private readonly ExtensionAttribute mExtAlternative;
		}

		/// <summary>
		/// Attribute indicating which OpenGL version is sufficient to support the underlying OpenGL extension.
		/// </summary>
		[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
		private class CoreVersionExtensionAttribute : Attribute
		{
			/// <summary>
			/// Construct a CoreExtensionAttribute specifying the OpenGL version.
			/// </summary>
			/// <param name="version"></param>
			public CoreVersionExtensionAttribute(GLVersion version)
			{
				// Store version
				mVersion = version;
			}

			/// <summary>
			/// Sufficient OpenGL version to support an OpenGL extension by a specific RenderContext instance.
			/// </summary>
			/// <param name="ctx">
			/// A <see cref="RenderContext"/> which is tested for supporting a core extension.
			/// </param>
			/// <exception cref="ArgumentNullException">
			/// Exception thrown in the case <paramref name="ctx"/> is null.
			/// </exception>
			public bool IsSupported(RenderContext ctx)
			{
				if (ctx == null)
					return (sCurrentGLVersion >= mVersion);
				return (ctx.Version >= mVersion);
			}

			/// <summary>
			/// Sufficient OpenGL version to support an OpenGL extension.
			/// </summary>
			private GLVersion mVersion;
		}

		/// <summary>
		/// Attribute indicating whether the field shall not indicate that a framework feature is supported.
		/// </summary>
		[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
		private class DisabledExtensionAttribute : Attribute
		{
			
		}

		/// <summary>
		/// Attribute indicating whether a field shall indicate an OpenGL implementation limit.
		/// </summary>
		[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
		private class ImplementationInfoAttribute : Attribute
		{
			/// <summary>
			/// Construct a ImplementationLimit.
			/// </summary>
			/// <param name="enum">
			/// A <see cref="System.Int32"/> that specifies the OpenGL enumeration value to used with Gl.Get and Gl.GetString routines.
			/// </param>
			public ImplementationInfoAttribute(int @enum)
			{
				mEnumValue = @enum;
			}

			/// <summary>
			/// The enumeration value representing the limit.
			/// </summary>
			public int EnumValue { get { return (mEnumValue); } }

			/// <summary>
			/// In the case the limit is composed by an array, this property specify the array length.
			/// </summary>
			public uint ArrayLenght { get { return (mArrayLength); } set { mArrayLength = value; } }

			/// <summary>
			/// The enumeration value representing the limit.
			/// </summary>
			private int mEnumValue;

			/// <summary>
			/// In the case the limit is composed by an array, this field specify the array length.
			/// </summary>
			private uint mArrayLength = 0;
		}

		/// <summary>
		/// Attribute indicating which OpenGL extension string is required for supporting a query to an implementation limit.
		/// </summary>
		/// <remarks>
		/// 
		/// </remarks>
		[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
		private class ImplementationInfoExtensionAttribute : ExtensionAttribute
		{
			/// <summary>
			/// Construct a ImplementationLimitExtensionAttribute.
			/// </summary>
			/// <param name="extString">
			/// A <see cref="System.String"/> that specifies the main extension name string.
			/// </param>
			/// <param name="altStrings">
			/// A <see cref="T:System.String[]"/> that specifies the alternative extension name strings.
			/// </param>
			public ImplementationInfoExtensionAttribute(string extString, params string[] altStrings) : base(extString, altStrings)
			{
				
			}
		}

		#endregion

		/// <summary>
		/// Information about OpenGL extension support.
		/// </summary>
		[DebuggerDisplay("Supported: {Supported}; Core: {CoreSupport}")]
		public struct ExtSupport
		{
			/// <summary>
			/// Determine whether this extension is generally supported.
			/// </summary>
			/// <remarks>
			/// In the case this flag is set to true, the extension is generally supported. For specific information
			/// about extension support, see other structure members.
			/// </remarks>
			public bool Supported;

			/// <summary>
			/// Determine whether this extension is supported because current core implementation include it.
			/// </summary>
			/// <remarks>
			/// Many extension are merged in the OpenGL core implementation. In some cases, the extension specification
			/// is applied "as is", but it can change semantics in order fit in the current OpenGL implementation.
			/// 
			/// In the case this flag is set, the OpenGL core specification shall be taken into account instead of the
			/// extension specification; otherwise, the extension specification shall be taken into account.
			/// </remarks>
			public bool CoreSupport;
		}

		/// <summary>
		/// OpenGL implementation capabilities.
		/// </summary>
		public class Capabilities
		{
			#region Information

			/// <summary>
			/// The graphic adapter used as renderer.
			/// </summary>
			[ImplementationInfo(Gl.RENDERER)]
			public string Renderer;

			/// <summary>
			/// The renderer vendor.
			/// </summary>
			[ImplementationInfo(Gl.VENDOR)]
			public string Vendor;

			/// <summary>
			/// The implemented OpenGL version.
			/// </summary>
			[ImplementationInfo(Gl.VERSION)]
			public string Version;

			/// <summary>
			/// The implemented OpenGL Shading Language version.
			/// </summary>
			[ImplementationInfo(Gl.SHADING_LANGUAGE_VERSION)]
			public string ShadingLanguageVersion;

			/// <summary>
			/// Extensions implemeneted by renderer.
			/// </summary>
			[ImplementationInfo(Gl.EXTENSIONS)]
			public string Extensions;

			#endregion

			#region Render Context OpenGL Extentions (ARB)

			/// <summary>
			/// Multisample rendering availability flag (5. {GL|WGL|GLX}_ARB_multisample).
			/// </summary>
			/// <remarks>
			/// Core implementation differences
			///
			/// Multisampling was promoted from the GL ARB multisample extension; The
			/// definition of the extension was changed slightly to support both multisampling and
			/// supersampling implementations.
			/// </remarks>
			[RequiredExtension("GL_ARB_multisample", "WGL_ARB_multisample", "GLX_ARB_multisample")]
			[MinVersionExtension(GLVersion.Version_1_2_1)]
			[CoreVersionExtension(GLVersion.Version_1_3)]
			public ExtSupport Multisample;

			/// <summary>
			/// Depth texture format available (22. GL_ARB_depth_texture).
			/// </summary>
			[RequiredExtension("GL_ARB_depth_texture")]
			[MinVersionExtension(GLVersion.Version_1_1)]
			[CoreVersionExtension(GLVersion.Version_1_4)]
			public ExtSupport DepthTexture;

			/// <summary>
			/// Vertex buffer object available (28. GL_ARB_vertex_buffer_object, GLX_ARB_vertex_buffer_object).
			/// </summary>
			/// <remarks>
			/// <para>
			/// Core implementation:
			/// 
			/// Buffer objects allow various types of data (especially vertex array data) to be
			/// cached in high-performance graphics memory on the server, thereby increasing
			/// the rate of data transfers to the GL.
			/// Buffer objects were promoted from the GL ARB vertex buffer object extension.
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_ARB_vertex_buffer_object", "GLX_ARB_vertex_buffer_object")]
			[CoreVersionExtension(GLVersion.Version_1_5)]
			public ExtSupport VertexBufferObject;

			/// <summary>
			/// Occlusion query available (29. GL_ARB_occlusion_query).
			/// </summary>
			/// <remarks>
			/// <para>
			/// Core implementation has no differences.
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_ARB_occlusion_query")]
			[MinVersionExtension(GLVersion.Version_1_4)]
			[CoreVersionExtension(GLVersion.Version_1_5)]
			public ExtSupport OcclusionQuery;

			/// <summary>
			/// Shader objects (30. GL_ARB_shader_objects)
			/// </summary>
			/// <remarks>
			/// <para>
			/// Core implementation differences (Shader Objects)
			/// 
			/// Shader objects provides mechanisms necessary to manage shader and program objects.
			/// Shader objects were promoted from the GL ARB shader objects extension.
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_ARB_shader_objects")]
			[CoreVersionExtension(GLVersion.Version_2_0)]
			public ExtSupport ShaderObjects;

			/// <summary>
			/// Vertex shader extension (31. GL_ARB_vertex_shader).
			/// </summary>
			/// <remarks>
			/// <para>
			/// Core implementation differences (Changes To Shader APIs)
			/// 
			/// Small changes to the APIs for managing shader and program objects were made
			/// in the process of promoting the shader extensions to the OpenGL 2.0 core. These
			/// changes do not affect the functionality of the shader APIs, but include use of the
			/// existing uint core GL type rather than the new handleARB type introduced by
			/// the extensions, and changes in some function names, for example mapping the extension
			/// function CreateShaderObjectARB into the core function CreateShader.
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_ARB_vertex_shader")]
			[CoreVersionExtension(GLVersion.Version_2_0)]
			public ExtSupport VertexShader;

			/// <summary>
			/// Fragment shader extension (32. GL_ARB_fragment_shader).
			/// </summary>
			/// <remarks>
			/// <para>
			/// Core implementation differences (Changes To Shader APIs)
			/// 
			/// Small changes to the APIs for managing shader and program objects were made
			/// in the process of promoting the shader extensions to the OpenGL 2.0 core. These
			/// changes do not affect the functionality of the shader APIs, but include use of the
			/// existing uint core GL type rather than the new handleARB type introduced by
			/// the extensions, and changes in some function names, for example mapping the extension
			/// function CreateShaderObjectARB into the core function CreateShader.
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_ARB_fragment_shader")]
			[CoreVersionExtension(GLVersion.Version_2_0)]
			public ExtSupport FragmentShader;

			/// <summary>
			/// Shading language version support (33. GL_ARB_shading_language_100).
			/// </summary>
			[RequiredExtension("GL_ARB_shading_language_100")]
			[CoreVersionExtension(GLVersion.Version_2_0)]
			public ExtSupport ShadingLanguage100;

			/// <summary>
			/// Texture Non Power Of Two extension (34. GL_ARB_texture_non_power_of_two).
			/// </summary>
			[RequiredExtension("GL_ARB_texture_non_power_of_two")]
			[CoreVersionExtension(GLVersion.Version_2_0)]
			public ExtSupport TextureNPOT;

			/// <summary>
			/// Rectangle texture extension (38. GL_ARB_texture_rectangle).
			/// </summary>
			[RequiredExtension("GL_ARB_texture_rectangle")]
			[MinVersionExtension(GLVersion.Version_1_1)]
			[CoreVersionExtension(GLVersion.Version_3_1)]
			public ExtSupport TextureRectangle;

			/// <summary>
			/// Half float pixel extension (40. GL_ARB_half_float_pixel).
			/// </summary>
			[RequiredExtension("GL_ARB_half_float_pixel")]
			[MinVersionExtension(GLVersion.Version_1_5)]
			[CoreVersionExtension(GLVersion.Version_3_0)]
			public ExtSupport HalfFloatPixel;

			/// <summary>
			/// Floating point texture extention (41. GL_ARB_texture_float).
			/// </summary>
			[RequiredExtension("GL_ARB_texture_float")]
			[MinVersionExtension(GLVersion.Version_1_1)]
			[CoreVersionExtension(GLVersion.Version_3_0)]
			public ExtSupport TextureFloat;

			/// <summary>
			/// Floating-point depth texture extension (43. GL_ARB_depth_buffer_float).
			/// </summary>
			[RequiredExtension("GL_ARB_depth_buffer_float")]
			[MinVersionExtension(GLVersion.Version_2_0)]
			public ExtSupport DepthTextureFloat;

			/// <summary>
			/// Framebuffer object (45. GL_ARB_framebuffer_object).
			/// </summary>
			[RequiredExtension("GL_ARB_framebuffer_object")]
			[MinVersionExtension(GLVersion.Version_1_0, "GL_EXT_texture")]
			[CoreVersionExtension(GLVersion.Version_3_0)]
			public ExtSupport FrambufferObject;

			/// <summary>
			/// sRGB framebuffer extension (46. GL_ARB_framebuffer_sRGB).
			/// </summary>
			[RequiredExtension("GL_ARB_framebuffer_sRGB", "WGL_ARB_framebuffer_sRGB", "GLX_ARB_framebuffer_sRGB")]
			[SubsetExtension("GL_EXT_framebuffer_sRGB", "GLX_EXT_framebuffer_sRGB", "WGL_EXT_framebuffer_sRGB")]
			[MinVersionExtension(GLVersion.Version_1_1)]
			[CoreVersionExtension(GLVersion.Version_3_0)]
			public ExtSupport FramebufferSRGB;

			/// <summary>
			/// Geometry shader extension (47. GL_ARB_geometry_shader4).
			/// </summary>
			[RequiredExtension("GL_ARB_geometry_shader4")]
			[MinVersionExtension(GLVersion.Version_1_1)]
			[CoreVersionExtension(GLVersion.Version_3_2)]
			public ExtSupport GeometryShader;

			/// <summary>
			/// Vertex array (54. GL_ARB_vertex_array_object).
			/// </summary>
			[RequiredExtension("GL_ARB_vertex_array_object")]
			[MinVersionExtension(GLVersion.Version_2_1)]
			public ExtSupport VertexArrayObject;

			/// <summary>
			/// Texture RG format available (53. GL_ARB_texture_rg).
			/// </summary>
			[RequiredExtension("GL_ARB_texture_rg")]
			[MinVersionExtension(GLVersion.Version_1_1)]
			[CoreVersionExtension(GLVersion.Version_3_0)]
			public ExtSupport TextureRg;

			/// <summary>
			/// Uniform buffer object extension (57. GL_ARB_uniform_buffer_object);
			/// </summary>
			[RequiredExtension("GL_ARB_uniform_buffer_object")]
			[MinVersionExtension(GLVersion.Version_1_5)]
			[CoreVersionExtension(GLVersion.Version_3_1)]
			public ExtSupport UniformBufferObject;

			/// <summary>
			/// Compatibility extension (58. GL_ARB_compatibility).
			/// </summary>
			[RequiredExtension("GL_ARB_compatibility")]
			public ExtSupport Compatibility;

			/// <summary>
			/// Cube map texture extension (65. GL_ARB_texture_cube_map).
			/// </summary>
			[RequiredExtension("GL_ARB_texture_cube_map")]
			[CoreVersionExtension(GLVersion.Version_1_3)]
			public ExtSupport TextureCubeMap;

			/// <summary>
			/// Shading language include preprocessor directive (76. GL_ARB_shading_language_include).
			/// </summary>
			[RequiredExtension("GL_ARB_shading_language_include")]
			[MinVersionExtension(GLVersion.Version_1_0)]
			[DisabledExtension()]
			public ExtSupport ShaderInclude;

			/// <summary>
			/// Occlusion query (2th version) available (80. GL_ARB_occlusion_query2).
			/// </summary>
			[RequiredExtension("GL_ARB_occlusion_query2")]
			[MinVersionExtension(GLVersion.Version_1_0)]
			[CoreVersionExtension(GLVersion.Version_3_3)]
			public ExtSupport OcclusionQuery2;

			/// <summary>
			/// Texture swizzle available (84. GL_ARB_texture_swizzle).
			/// </summary>
			/// <remarks>
			/// The GL_ARB_texture_swizzle and GL_EXT_texture_swizzle are exactly the same extention, having the same functionalities, declarations and
			/// specification. Indeed, they share also the minimum version and the core version.
			/// </remarks>
			[RequiredExtension("GL_ARB_texture_swizzle", "GL_EXT_texture_swizzle")]
			[MinVersionExtension(GLVersion.Version_1_0)]
			[CoreVersionExtension(GLVersion.Version_3_3)]
			public ExtSupport TextureSwizzle;

			/// <summary>
			/// Timer query available (85. GL_ARB_timer_query).
			/// </summary>
			[RequiredExtension("GL_ARB_timer_query")]
			public ExtSupport TimerQuery;

			/// <summary>
			/// 5th generation shader available (88. GL_ARB_gpu_shader5).
			/// </summary>
			[RequiredExtension("GL_ARB_gpu_shader5")]
			public ExtSupport GpuShader5;

			/// <summary>
			/// Double precision floating-point shader uniform/input/instructions available (89. GL_ARB_gpu_shader_fp64).
			/// </summary>
			[RequiredExtension("GL_ARB_gpu_shader_fp64")]
			public ExtSupport GpuShaderFp64;

			/// <summary>
			/// Texture buffer object available (92. GL_ARB_texture_buffer_object_rgb32).
			/// </summary>
			[RequiredExtension("GL_ARB_texture_buffer_object_rgb32")]
			public ExtSupport TextureBufferObjectRgb32;

			#endregion

			#region Render Context OpenGL Extentions (EXT)

			/// <summary>
			/// Constant color blending functions (2. GL_EXT_blend_color).
			/// </summary>
			[RequiredExtension("GL_EXT_texture")]
			public ExtSupport BlendColor;

			/// <summary>
			/// Texture internal formats (4. GL_EXT_texture).
			/// </summary>
			/// <remarks>
			/// <para>
			/// Core implementation (Texture Image Formats)
			/// 
			/// Stored texture arrays have a format, known as the internal format, rather than a
			/// simple count of components. The internal format is represented as a single enumerated
			/// value, indicating both the organization of the image data (LUMINANCE,
			/// RGB, etc.) and the number of bits of storage for each image component. Clients
			/// can use the internal format specification to suggest the desired storage precision
			/// of texture images. New base internal formats, ALPHA and INTENSITY, provide
			/// new texture environment operations. These additions match those of a subset of
			/// the GL EXT texture extension.
			/// </para>
			/// <para>
			/// Core implementation (Texture Replace Environment)
			/// 
			/// A common use of texture mapping is to replace the color values of generated
			/// fragments with texture color data. This could be specified only indirectly in GL
			/// version 1.0, which required that client specified white geometry be modulated
			/// by a texture. GL version 1.1 allows such replacement to be specified explicitly,
			/// possibly improving performance. These additions match those of a subset of the
			/// GL EXT texture extension.
			/// </para>
			/// <para>
			/// Core implementation (Texture Proxies)
			/// 
			/// Texture proxies allow a GL implementation to advertise different maximum texture
			/// image sizes as a function of some other texture parameters, especially of the
			/// internal image format. Clients may use the proxy query mechanism to tailor their
			/// use of texture resources at run time. The proxy interface is designed to allow such
			/// queries without adding new routines to the GL interface. These additions match
			/// those of a subset of the GL EXT texture extension, except that implementations
			/// return allocation information consistent with support for complete mipmap arrays.
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_EXT_texture")]
			[CoreVersionExtension(GLVersion.Version_1_1)]
			public ExtSupport Texture;

			/// <summary>
			/// Texture 3D extension (6. EXT_texture3D).
			/// </summary>
			[RequiredExtension("GL_EXT_texture3D")]
			[CoreVersionExtension(GLVersion.Version_1_2)]
			public ExtSupport Texture3D;

			/// <summary>
			/// Sub-texture specification (9. GL_EXT_subtexture).
			/// </summary>
			/// <remarks>
			/// Core implementation
			/// 
			/// Texture array data can be specified from framebuffer memory, as well as from
			/// client memory, and rectangular subregions of texture arrays can be redefined either
			/// from client or framebuffer memory. These additions match those defined by the
			/// GL EXT copy texture and GL EXT subtexture extensions.
			/// </remarks>
			[RequiredExtension("GL_EXT_subtexture")]
			[RequiredExtension("GL_EXT_texture")]
			[CoreVersionExtension(GLVersion.Version_1_1)]
			public ExtSupport SubTexture;

			/// <summary>
			/// Texture copy (10. GL_EXT_texture_object).
			/// </summary>
			/// <remarks>
			/// Core implementation
			/// 
			/// Texture array data can be specified from framebuffer memory, as well as from
			/// client memory, and rectangular subregions of texture arrays can be redefined either
			/// from client or framebuffer memory. These additions match those defined by the
			/// GL EXT copy texture and GL EXT subtexture extensions.
			/// </remarks>
			[RequiredExtension("GL_EXT_copy_texture")]
			[RequiredExtension("GL_EXT_texture")]
			[CoreVersionExtension(GLVersion.Version_1_1)]
			public ExtSupport CopyTexture;

			/// <summary>
			/// CMYKA pixel format (18. EXT_cmyka).
			/// </summary>
			[RequiredExtension("GL_EXT_cmyka")]
			public ExtSupport CmykaFormat;

			/// <summary>
			/// Texture object (20. GL_EXT_texture_object).
			/// </summary>
			/// <remarks>
			/// <para>
			/// Core implementation
			/// 
			/// A set of texture arrays and their related texture state can be treated as a single
			/// object. Such treatment allows for greater implementation efficiency when multiple
			/// arrays are used. In conjunction with the subtexture capability, it also allows
			/// clients to make gradual changes to existing texture arrays, rather than completely
			/// redefining them. These additions match those of the GL EXT texture object
			/// extension, with slight additions to the texture residency semantics.
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_EXT_texture_object")]
			[CoreVersionExtension(GLVersion.Version_1_1)]
			public ExtSupport TextureObject;

			/// <summary>
			/// RGB(A)/BGR(A) packed pixel internal formats (23. Gl_EXT_packed_pixels).
			/// </summary>
			/// <remarks>
			/// <para>
			/// Core implementation:
			/// 
			/// Packed pixels in client memory are represented entirely by one unsigned byte,
			/// one unsigned short, or one unsigned integer. The fields with the packed pixel are
			/// not proper machine types, but the pixel as a whole is. Thus the pixel storage modes
			/// and their unpacking counterparts all work correctly with packed pixels.
			/// The additions match those of the GL EXT packed pixels extension, with the
			/// further addition of reversed component order packed formats
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_EXT_packed_pixels")]
			[CoreVersionExtension(GLVersion.Version_1_2)]
			public ExtSupport PackedFormats;

			/// <summary>
			/// Blending separate function (37. GL_EXT_blend_minmax)
			/// </summary>
			[RequiredExtension("GL_EXT_blend_minmax")]
			public ExtSupport BlendMinMax;

			/// <summary>
			/// Blending subtract equations (38. GL_EXT_blend_subtract)
			/// </summary>
			[RequiredExtension("GL_EXT_blend_subtract")]
			public ExtSupport BlendSubtract;

			/// <summary>
			/// BGRA pixel format (128. GL_EXT_bgra).
			/// </summary>
			/// <remarks>
			/// <para>
			/// Core implementation:
			/// 
			/// BGRA extends the list of client memory color formats. Specifically, it provides
			/// a component order matching file and framebuffer formats common on Windows
			/// platforms. The additions match those of the GL EXT bgra extension.
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_EXT_bgra")]
			[CoreVersionExtension(GLVersion.Version_1_2)]
			public ExtSupport BgraFormat;

			/// <summary>
			/// Blending separate function (173. GL_EXT_blend_func_separate)
			/// </summary>
			[RequiredExtension("GL_EXT_blend_func_separate")]
			public ExtSupport BlendFuncSeparate;

			/// <summary>
			/// Yuv 422 pixel format (178. GL_EXT_422_pixels).
			/// </summary>
			[RequiredExtension("GL_EXT_422_pixels")]
			public ExtSupport Yuv422Format;

			/// <summary>
			/// Blending separate equation (299. GL_EXT_blend_equation_separate)
			/// </summary>
			[RequiredExtension("GL_EXT_blend_equation_separate")]
			public ExtSupport BlendEquationSeparate;

			/// <summary>
			/// Texture sRGB internal format (315. GL_EXT_texture_sRGB).
			/// </summary>
			/// <remarks>
			/// <para>
			/// Core implementation
			/// 
			/// New uncompressed and compressed color texture formats with sRGB color components
			/// are defined. The sRGB color space is based on typical (non-linear) monitor
			/// characteristics expected in a dimly lit office. It has been standardized by the International
			/// Electrotechnical Commission (IEC) as IEC 61966-2-1. The sRGB color
			/// space roughly corresponds to 2.2 gamma correction.
			/// sRGB textures was promoted from the GL EXT texture sRGB extension.
			/// Specific compressed sRGB internal formats defined by the extension were not included
			/// in OpenGL 2.1, while the generic uncompressed and compressed formats
			/// were retained
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_EXT_texture_sRGB")]
			[MinVersionExtension(GLVersion.Version_1_1)]
			[CoreVersionExtension(GLVersion.Version_2_1)]
			public ExtSupport TextureSRGB;

			/// <summary>
			/// Framebuffer object (310. GL_EXT_framebuffer_object).
			/// </summary>
			[RequiredExtension("GL_EXT_framebuffer_object")]
			[MinVersionExtension(GLVersion.Version_1_1)]
			public ExtSupport FrambufferObject_EXT;

			/// <summary>
			/// 4th shader generation available (326. GL_EXT_gpu_shader4).
			/// </summary>
			[RequiredExtension("GL_EXT_gpu_shader4")]
			[MinVersionExtension(GLVersion.Version_2_0)]
			[CoreVersionExtension(GLVersion.Version_3_0)]
			public ExtSupport GpuShader4;

			/// <summary>
			/// sRGB framebuffer extension (337. GL_EXT_framebuffer_sRGB).
			/// </summary>
			/// <remarks>
			/// This extention is almost similar to the extention GL_ARB_framebuffer_sRGB, except for one particular; the following
			/// text shall be removed in order to obtain an equivalent GL_ARB_framebuffer_sRGB specification:
			/// <para>
			/// Accepted by the <i>pname</i> parameter of GetBooleanv, GetIntegerv,
			/// GetFloatv, and GetDoublev:
			///			FRAMEBUFFER_SRGB_CAPABLE_EXT                 0x8DBA
			/// </para>
			/// </remarks>
			[RequiredExtension("GL_EXT_framebuffer_sRGB", "GLX_EXT_framebuffer_sRGB", "WGL_EXT_framebuffer_sRGB")]
			[MinVersionExtension(GLVersion.Version_1_1)]
			public ExtSupport FramebufferSRGB_EXT;

			/// <summary>
			/// Texture integer extension (343. GL_EXT_texture_integer).
			/// </summary>
			[RequiredExtension("GL_EXT_texture_integer")]
			[MinVersionExtension(GLVersion.Version_2_0)]
			[CoreVersionExtension(GLVersion.Version_3_0)]
			public ExtSupport TextureInteger;

			#endregion

			#region Render Context OpenGL Extentions (WGL/GLX)

			/// <summary>
			/// Fundation for querying OpenGL extension using WGL.
			/// </summary>
			[RequiredExtension("WGL_ARB_extensions_string")]
			public ExtSupport ExtensionString;

			/// <summary>
			/// Choose a window pixel format (9. WGL_ARB_pixel_format).
			/// </summary>
			[RequiredExtension("WGL_ARB_pixel_format")]
			[RequiredExtension("WGL_ARB_extensions_string")]
			public ExtSupport ExtendedPixelFormat;

			/// <summary>
			/// Create a compatible context (55. WGL_ARB_create_context, 56. GLX_ARB_create_context).
			/// </summary>
			[RequiredExtension("WGL_ARB_create_context", "GLX_ARB_create_context")]
			[RequiredExtension("WGL_ARB_extensions_string")]
			[CoreVersionExtension(GLVersion.Version_3_2)]
			public ExtSupport CreateContext;

			/// <summary>
			/// Create a forward compatible context (74. WGL_ARB_create_context_profile, 75. GLX_ARB_create_context_profile).
			/// </summary>
			[RequiredExtension("WGL_ARB_create_context_profile", "GLX_ARB_create_context_profile")]
			[RequiredExtension("WGL_ARB_extensions_string")]
			[CoreVersionExtension(GLVersion.Version_3_2)]
			public ExtSupport CreateContextProfile;

			#endregion

			#region Render Context Limits

			#region Viewport Limits

			/// <summary>
			/// Maximum viewport dimensions (width and height).
			/// </summary>
			[ImplementationInfo(Gl.MAX_VIEWPORT_DIMS, ArrayLenght = 2)]
			public int[] MaxViewport = new int[] { 0, 0 };

			#endregion

			#region  Frambuffer Object Limits

			/// <summary>
			/// The maximum number of color attachments that the frambuffer support.
			/// </summary>
			[ImplementationInfo(Gl.MAX_COLOR_ATTACHMENTS)]
			[ImplementationInfoExtension("GL_ARB_framebuffer_object", "GL_EXT_framebuffer_object")]
			public int MaxColorAttachments;

			/// <summary>
			/// The maximum size of render buffers.
			/// </summary>
			[ImplementationInfo(Gl.MAX_RENDERBUFFER_SIZE)]
			[ImplementationInfoExtension("GL_ARB_framebuffer_object", "GL_EXT_framebuffer_object")]
			public int MaxRenderBufferSize;

			#endregion

			#region Multisampling Limits

			/// <summary>
			/// Maximum sample bits for framebuffer attachments standard format.
			/// </summary>
			[ImplementationInfo(Gl.MAX_SAMPLES)]
			public int MaxSamples = 0;

			/// <summary>
			/// Maximum sample bits for framebuffer attachments with integer format.
			/// </summary>
			[ImplementationInfo(Gl.MAX_INTEGER_SAMPLES)]
			public int MaxIntegerSamples = 0;

			#endregion

			#region Drawing Limits

			/// <summary>
			/// The maximum number of color attachments that a shader support.
			/// </summary>
			[ImplementationInfo(Gl.MAX_DRAW_BUFFERS)]
			public int MaxDrawBuffers;

			/// <summary>
			/// Maximum number of drawable attribute array length.
			/// </summary>
			[ImplementationInfo(Gl.MAX_ELEMENTS_VERTICES)]
			public int MaxElementsVertices;

			/// <summary>
			/// Maximum number of drawable attribute elements.
			/// </summary>
			[ImplementationInfo(Gl.MAX_ELEMENTS_INDICES)]
			public int MaxElementsIndices;

			#endregion

			#region Texture Size Limits

			/// <summary>
			/// Maximum 2D texture extents.
			/// </summary>
			[ImplementationInfo(Gl.MAX_TEXTURE_SIZE)]
			public int MaxTexture2DSize;

			/// <summary>
			/// Maximum 3D texture extents.
			/// </summary>
			[ImplementationInfo(Gl.MAX_3D_TEXTURE_SIZE)]
			[ImplementationInfoExtension("GL_EXT_texture3D")]
			public int MaxTexture3DSize;

			/// <summary>
			/// Maximum rectangle texture extents.
			/// </summary>
			[ImplementationInfo(Gl.MAX_RECTANGLE_TEXTURE_SIZE)]
			[ImplementationInfoExtension("GL_ARB_texture_rectangle")]
			public int MaxTextureRectSize;

			/// <summary>
			/// Maximum cube map texture extents.
			/// </summary>
			[ImplementationInfo(Gl.MAX_CUBE_MAP_TEXTURE_SIZE)]
			[ImplementationInfoExtension("GL_ARB_texture_cube_map")]
			public int MaxTextureCubeSize;

			#endregion

			#region Shader Attributes

			/// <summary>
			/// Maximum number of varying vertex attributes.
			/// </summary>
			[ImplementationInfo(Gl.MAX_VERTEX_ATTRIBS)]
			[ImplementationInfoExtension("GL_ARB_vertex_shader")]
			public int MaxVertexAttrib;

			/// <summary>
			/// Maximum number of outputs for vertex shader.
			/// </summary>
			[ImplementationInfo(Gl.MAX_VERTEX_OUTPUT_COMPONENTS)]
			[ImplementationInfoExtension("GL_ARB_vertex_shader")]
			public int MaxVertexOutputsComponents = 0;

			/// <summary>
			/// Maximum number of inputs for fragment shader.
			/// </summary>
			[ImplementationInfo(Gl.MAX_FRAGMENT_INPUT_COMPONENTS)]
			[ImplementationInfoExtension("GL_ARB_fragment_shader")]
			public int MaxFragmentInputComponents;

			#endregion

			#region Geometry Shader Output

			/// <summary>
			/// Maximum vertices outputtable by a geometry shader.
			/// </summary>
			[ImplementationInfo(Gl.MAX_GEOMETRY_OUTPUT_VERTICES)]
			[ImplementationInfoExtension("GL_ARB_geometry_shader4")]
			public int MaxGeometryOutputVertices = 0;

			#endregion

			#region Texture Cooordinate and Image Units

			/// <summary>
			/// Maximum number of texture units usable  by a vertex shader.
			/// </summary>
			[ImplementationInfo(Gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)]
			[ImplementationInfoExtension("GL_ARB_vertex_shader")]
			public int MaxVertexTextureImageUnits;

			/// <summary>
			/// Maximum number of texture units usable  by a geometry shader.
			/// </summary>
			[ImplementationInfo(Gl.MAX_GEOMETRY_TEXTURE_IMAGE_UNITS)]
			[ImplementationInfoExtension("GL_ARB_geometry_shader4")]
			public int MaxGeometryTextureImageUnits;

			/// <summary>
			/// Maximum number of texture coordinate units usable by a fragment shader.
			/// </summary>
			[ImplementationInfo(Gl.MAX_TEXTURE_COORDS)]
			[ImplementationInfoExtension("GL_ARB_fragment_shader")]
			public int MaxFragmentTextureCoordUnits;

			/// <summary>
			/// Maximum number of texture units usable  by a fragment shader.
			/// </summary>
			[ImplementationInfo(Gl.MAX_TEXTURE_IMAGE_UNITS)]
			[ImplementationInfoExtension("GL_ARB_fragment_shader")]
			public int MaxFragmentTextureImageUnits;

			/// <summary>
			/// Maximum number of texture image units usable by all shader program stages at once.
			/// </summary>
			[ImplementationInfo(Gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)]
			[ImplementationInfoExtension("GL_ARB_shader_program")]
			public int MaxCombinedTextureImageUnits;

			#endregion

			#region Default Uniform Block

			/// <summary>
			/// Maximum number of components for a vertex shader uniform variable.
			/// </summary>
			[ImplementationInfo(Gl.MAX_VERTEX_UNIFORM_COMPONENTS)]
			[ImplementationInfoExtension("GL_ARB_vertex_shader")]
			public int MaxVertexUniformComponents;

			/// <summary>
			/// Maximum number of components for a geometry shader uniform variable.
			/// </summary>
			[ImplementationInfo(Gl.MAX_GEOMETRY_UNIFORM_COMPONENTS)]
			[ImplementationInfoExtension("GL_ARB_geometry_shader4")]
			public int MaxGeometryUniformComponents;

			/// <summary>
			/// Maximum number of components for a fragment shader uniform variable.
			/// </summary>
			[ImplementationInfo(Gl.MAX_FRAGMENT_UNIFORM_COMPONENTS)]
			[ImplementationInfoExtension("GL_ARB_fragment_shader")]
			public int MaxFragmentUniformComponents;

			#endregion

			#region Uniform Blocks

			/// <summary>
			/// Maximum number of uniform blocks on a vertex shader.
			/// </summary>
			[ImplementationInfo(Gl.MAX_VERTEX_UNIFORM_BLOCKS)]
			[ImplementationInfoExtension("GL_ARB_vertex_shader")]
			[ImplementationInfoExtension("GL_ARB_uniform_buffer_object")]
			public int MaxVertexUniformBlocks;

			/// <summary>
			/// Maximum number of uniform blocks on a fragment shader.
			/// </summary>
			[ImplementationInfo(Gl.MAX_FRAGMENT_UNIFORM_BLOCKS)]
			[ImplementationInfoExtension("GL_ARB_fragment_shader")]
			[ImplementationInfoExtension("GL_ARB_uniform_buffer_object")]
			public int MaxFragmentUniformBlocks;

			/// <summary>
			/// Maximum number of combined uniform blocks.
			/// </summary>
			[ImplementationInfo(Gl.MAX_COMBINED_UNIFORM_BLOCKS)]
			[ImplementationInfoExtension("GL_ARB_uniform_buffer_object")]
			public int MaxCombinedUniformBlocks;

			/// <summary>
			/// Maximum size for an uniform block.
			/// </summary>
			[ImplementationInfo(Gl.MAX_UNIFORM_BLOCK_SIZE)]
			[ImplementationInfoExtension("GL_ARB_uniform_buffer_object")]
			public int MaxUniformBlockSize;

			/// <summary>
			/// Maximum number of indexed bindings for an uniform buffer.
			/// </summary>
			[ImplementationInfo(Gl.MAX_UNIFORM_BUFFER_BINDINGS)]
			[ImplementationInfoExtension("GL_ARB_uniform_buffer_object")]
			public int MaxUniformBufferBindings;

			/// <summary>
			/// The required offset alignment for binding an uniform buffer with an offset.
			/// </summary>
			[ImplementationInfo(Gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT)]
			[ImplementationInfoExtension("GL_ARB_uniform_buffer_object")]
			public int UniformBufferOffsetAlignment;

			#endregion

			#endregion

			#region Window System Pixel Formats

			/// <summary>
			/// Supported pixel formats by the current window system.
			/// </summary>
			public PixelFormatCollection WindowPixelFormats = null;

			#endregion
		}

		/// <summary>
		/// Get rendering context capabilities of this RenderContext.
		/// </summary>
		/// <returns>
		/// A <see cref="Capabilities"/> which specify all available OpenGL implementation features and limits.
		/// </returns>
		/// <remarks>
		/// 
		/// </remarks>
		public Capabilities Caps
		{
			get {
				return (sRenderCapsDb[Version]);
			}
		}

		/// <summary>
		/// Get rendering context capabilities of the current OpenGL implementation.
		/// </summary>
		/// <returns>
		/// A <see cref="Capabilities"/> which specify all available OpenGL implementation features and limits.
		/// </returns>
		/// <remarks>
		/// 
		/// </remarks>
		public static Capabilities CurrentCaps
		{
			get {
				return (sRenderCaps);
			}
		}

		/// <summary>
		/// Query constant OpenGL informations.
		/// </summary>
		/// <param name="deviceContext">
		/// A <see cref="System.IntPtr"/> that specifies the device context used.
		/// </param>
		/// <param name="ctx">
		/// A <see cref="RenderContext"/> used for querying OpenGL extensions. The OpenGL version implemented by <paramref name="ctx"/>
		/// is used to check extension availability.
		/// </param>
		/// <remarks>
		/// This routine fetch the following informations from the current context:
		/// - OpenGL core implementation limits.
		/// - OpenGL extensions (ARB) availability and their limits.
		/// - OpenGL extensions (EXT) availability and their limits.
		/// - OpenGL extensions (NV) availability and their limits.
		/// - OpenGL extensions (ATI) availability and their limits.
		/// - OpenGL extensions (WGL/GLX) availability and their limits.
		/// </remarks>
		private static Capabilities QueryOpenGLInfo(IDeviceContext deviceContext, RenderContext ctx)
		{
			Capabilities caps = new Capabilities();
			FieldInfo[] capsFields = typeof(Capabilities).GetFields(BindingFlags.Public | BindingFlags.Instance);

			sLog.Debug("Querying capabilities of the OpenGL ({0}) renderer.", ctx != null ? ctx.Version.ToString() : "default");

			#region Platform Extension Reload

			// Since at this point there's a current OpenGL context, it's possible to use
			// {glx|wgl}GetExtensionsString to retrieve platform specific extensions

			switch (Environment.OSVersion.Platform) {
				case PlatformID.Win32NT:
				case PlatformID.Win32Windows:
					Wgl.SyncDelegates();
					break;
			}

			#endregion

			// These extensions are the minimum requirements for correct execution of
			// the framework.

			switch (Environment.OSVersion.Platform) {
				case PlatformID.Win32NT:
				case PlatformID.Win32Windows:
					// WGL_ARB_extensions_string
					CheckRequiredPlatformExtension(deviceContext, "ARB_extensions_string");
					break;
			}

			#region Generic Extension Query By Reflection
			
			// Only boolean fields are considered
			FieldInfo[] extsFields = Array.FindAll<FieldInfo>(capsFields, delegate(FieldInfo info) {
				return (info.FieldType == typeof(ExtSupport));
			});

			foreach (FieldInfo field in extsFields) {
				Attribute[] attrRequiredExtensions = Attribute.GetCustomAttributes(field, typeof(RequiredExtensionAttribute));
				Attribute[] attrSubsetExtensions = Attribute.GetCustomAttributes(field, typeof(SubsetExtensionAttribute));
				MinVersionExtensionAttribute attrMinVersion = (MinVersionExtensionAttribute)Attribute.GetCustomAttribute(field, typeof(MinVersionExtensionAttribute));
				CoreVersionExtensionAttribute attrCoreVersion = (CoreVersionExtensionAttribute)Attribute.GetCustomAttribute(field, typeof(CoreVersionExtensionAttribute));
				DisabledExtensionAttribute attrDisabledExtension = (DisabledExtensionAttribute)Attribute.GetCustomAttribute(field, typeof(DisabledExtensionAttribute));
				bool implemented = false;
				bool implementedCore = false;

				// Select attribute

				// Check minimum required OpenGL version
				if ((attrMinVersion != null) && (attrMinVersion.IsSupported(ctx, deviceContext) == false)) {
					sLog.Debug("\tOpenGL extension {0} ignored due required minimum version {1}", field.Name, attrMinVersion.MinVersion);
					continue;
				}

				// Check CORE support
				if (attrCoreVersion != null) {
					implementedCore = attrCoreVersion.IsSupported(ctx);

					if (implementedCore == false) {
						// Check whether all required extensions are implemented
						foreach (Attribute attrRequiredExtension in attrRequiredExtensions) {
							if (((RequiredExtensionAttribute)attrRequiredExtension).IsSupported(ctx, deviceContext) == false) {
								implemented = false;
								break;
							}
						}
					}

#if DEBUG
					if (implementedCore == true) {
						// Check the same extension support
						bool realSupport = true;
	
						foreach (Attribute attrRequiredExtension in attrRequiredExtensions) {
							if (((RequiredExtensionAttribute)attrRequiredExtension).IsSupported(ctx, deviceContext) == false) {
								realSupport = false;
								break;
							}
						}
	
						if (realSupport == false)
							sLog.Warn("OpenGL extension {0} implemented in core, but not listed", field.Name);
					}
#endif

					if (implementedCore)
						implemented = true;
				}


				// Check whether one of superset extensions are implemeneted
				if ((implemented == false) && (attrSubsetExtensions.Length > 0)) {
					foreach (Attribute attrSubsetExtension in attrSubsetExtensions) {
						if (((SubsetExtensionAttribute)attrSubsetExtension).IsSupported(ctx, deviceContext) == true) {
							implemented = true;
							break;
						}
					}
				}

				// Check whether the required extensions are artifically disabled
				if (attrDisabledExtension != null)
					implemented = false;

				// Set implemeneted state
				ExtSupport extSupport;

				extSupport.Supported = implemented;
				extSupport.CoreSupport = implementedCore;

				if (implemented == true)
					sLog.Debug("\tOpenGL extension {0} is supported{1}.", field.Name, implementedCore ? " (core support)" : String.Empty);
				else
					sLog.Debug("\tOpenGL extension {0} is not supported", field.Name);

				field.SetValue(caps, extSupport);
			}

			#endregion

			#region OpenGL Information By Reflection

			foreach (FieldInfo field in capsFields) {
				ImplementationInfoAttribute attrImplementationLimit = (ImplementationInfoAttribute)Attribute.GetCustomAttribute(field, typeof(ImplementationInfoAttribute));
				Attribute[] attrImplementationLimitExts = Attribute.GetCustomAttributes(field, typeof(ImplementationInfoExtensionAttribute));

				if (attrImplementationLimit != null) {
					MethodInfo getMethod;

					if ((attrImplementationLimitExts != null) && (attrImplementationLimitExts.Length > 0)) {
						foreach (Attribute attr in attrImplementationLimitExts) {
							ImplementationInfoExtensionAttribute infoAttribute = (ImplementationInfoExtensionAttribute)attr;

							if (infoAttribute.IsSupported(ctx, deviceContext) == false)
								continue;		// Query not supported
						}
					}

					// Determine which method is used to get the OpenGL limit
					if (field.FieldType != typeof(String)) {
						if (field.FieldType.IsArray == true)
							getMethod = typeof(Gl).GetMethod("Get", BindingFlags.Public|BindingFlags.Static, null, new Type[] { typeof(Int32), field.FieldType }, null);
						else
							getMethod = typeof(Gl).GetMethod("Get", BindingFlags.Public|BindingFlags.Static, null, new Type[] { typeof(Int32), field.FieldType.MakeByRefType() }, null);
					} else
						getMethod = typeof(Gl).GetMethod("GetString", BindingFlags.Public|BindingFlags.Static, null, new Type[] { typeof(Int32) }, null);

					if (getMethod != null) {
						if (field.FieldType != typeof(String)) {
							object obj;

							if (field.FieldType.IsArray == false)
								obj = Activator.CreateInstance(field.FieldType);
							else
								obj = Array.CreateInstance(field.FieldType.GetElementType(), attrImplementationLimit.ArrayLenght);
							object[] @params = new object[] { attrImplementationLimit.EnumValue, obj };
							getMethod.Invoke(null, @params);

							field.SetValue(caps, @params[1]);
						} else {
							string s = (string)getMethod.Invoke(null, new object[] { attrImplementationLimit.EnumValue });

							field.SetValue(caps, s);
						}
					} else
						throw new InvalidOperationException("Render.Capabilities field "+field.Name+" doesn't have a OpenGL compatible type");
				}
			}

			#endregion

			#region Window System Pixel Formats

			/* Pixel formats */
			if (ctx != null)
				caps.WindowPixelFormats = RenderContext.QueryPixelFormats(deviceContext, caps);
			else
				caps.WindowPixelFormats = RenderContext.QueryPixelFormats(deviceContext, RenderContext.CurrentCaps);

			#endregion

			return (caps);
		}

		/// <summary>
		/// Write to file detected OpenGL information.
		/// </summary>
		/// <param name="path">
		/// A <see cref="System.String"/> that specifies the path of the file.
		/// </param>
		public static void DumpOpenGLInfo(string path)
		{
			using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) {
				XmlSerializer xser = new XmlSerializer(typeof(Capabilities));

				xser.Serialize(fs, sRenderCaps);
			}
		}

		/// <summary>
		/// Check required OpenGL extension availability.
		/// </summary>
		/// <param name="ext">
		/// A <see cref="System.String"/> which specify the extension string to test for availability.
		/// </param>
		/// <exception cref="System.Exception">
		/// In the case the extension specified with <paramref name="ext"/> is not available,
		/// it throws the exception.
		/// </exception>
		private static void CheckRequiredGlExtension(string ext)
		{
			bool oglRequiredExt = (Gl.HasExtension(ext) == true);
			Debug.Assert(RenderException.CheckErrors() == true);
			if (oglRequiredExt == false)
				throw new Exception("current OpenGL implementation doesn't provide "+ext+" extension");
		}

		/// <summary>
		/// Check required OpenGL extension availability.
		/// </summary>
		/// <param name="ext">
		/// A <see cref="System.String"/> which specify the extension string to test for availability.
		/// </param>
		/// <param name="alternatives">
		/// A <see cref="T:System.String[]"/> that specifies a set of OpenGL extension alternatives which
		/// offer the same functionalities of the extension specified with the parameter <paramref name="ext"/>.
		/// </param>
		/// <exception cref="System.Exception">
		/// In the case the extension specified with <paramref name="ext"/> is not available, and none of
		/// the extension specified with <paramref name="alternatives"/>, it throws the exception.
		/// </exception>
		private static void CheckRequiredGlExtension(string ext, params string[] alternatives)
		{
			bool oglRequiredExt = Gl.HasExtension(ext);
			RenderException.DebugCheckErrors();

			// Check alternatives
			if (oglRequiredExt == false) {
				foreach (string alt in alternatives) {
					if ((oglRequiredExt = Gl.HasExtension(alt)) == true)
						break;
				}
			}
			if (oglRequiredExt == false)
				throw new Exception("current OpenGL implementation doesn't provide "+ext+" extension");
		}

		/// <summary>
		/// Check required OpenGL platform extension availability.
		/// </summary>
		/// <param name="ext">
		/// A <see cref="System.String"/> which specify the extension string to test for availability.
		/// </param>
		/// <exception cref="System.Exception">
		/// In the case the extension specified with <paramref name="ext"/> is not available,
		/// it throws the exception.
		/// </exception>
		private static void CheckRequiredPlatformExtension(IDeviceContext deviceContext, string ext)
		{
			bool oglRequiredExt;

			switch (Environment.OSVersion.Platform) {
				case PlatformID.Win32Windows:
				case PlatformID.Win32NT:
					oglRequiredExt = Wgl.HasExtension(deviceContext, "WGL_" + ext);
					break;
				case PlatformID.Unix:
					oglRequiredExt = Glx.HasExtension(deviceContext, "GLX_" + ext);
					break;
				default:
					throw new NotSupportedException();
			}
			RenderException.DebugCheckErrors();
			if (oglRequiredExt == false)
				throw new Exception("current OpenGL implementation doesn't provide "+ext+" extension");
		}
		
		/// <summary>
		/// Rendering context capabilities.
		/// </summary>
		/// <remarks>
		/// The <see cref="Capabilities"/> class is meant to represent a set of extensions and limits for a particoular OpenGL implementation. This
		/// means also that the render capabilities are dependent on the current context on the executing thread.
		/// </remarks>
		private static readonly Capabilities sRenderCaps = new Capabilities();

		/// <summary>
		/// 
		/// </summary>
		private static readonly Dictionary<GLVersion, Capabilities> sRenderCapsDb = new Dictionary<GLVersion,Capabilities>();

		#endregion

		#region Device Pixel Formats

		/// <summary>
		/// Pixel format description.
		/// </summary>
		[DebuggerDisplay("Window: {RenderWindow}, Buffer: {RenderBuffer}, Color: {ColorBits}, Depth: {DepthBits}, Stencil: {StencilBits}, Multisample: {MultisampleBits}, DoubleBuffer: {DoubleBuffer}")]
		public struct PixelFormat
		{
			/// <summary>
			/// Pixel format index.
			/// </summary>
			public int FormatIndex;

			/// <summary>
			/// Flag indicating whether this pixel format provide canonical (normalized) unsigned integer RGBA color.
			/// </summary>
			public bool RgbaUnsigned;
			/// <summary>
			/// Flag indicating whether this pixel format provide RGBA color composed by single-precision floating-point.
			/// </summary>
			public bool RgbaFloat;

			/// <summary>
			/// Pixel format can be used for rendering on windows.
			/// </summary>
			public bool RenderWindow;
			/// <summary>
			/// Pixel format can be used for rendering on memory buffers.
			/// </summary>
			public bool RenderBuffer;
			/// <summary>
			/// Pixel format can be used for rendering on pixel buffer objects.
			/// </summary>
			public bool RenderPBuffer;

			/// <summary>
			/// Pixel format support double buffering.
			/// </summary>
			public bool DoubleBuffer;
			/// <summary>
			/// Method used for swapping back buffers.
			/// </summary>
			/// <remarks>
			/// It can assume the values Wgl.SWAP_EXCHANGE, SWAP_COPY, or 
			/// SWAP_UNDEFINED in the case DoubleBuffer is false.
			/// </remarks>
			public int SwapMethod;
			/// <summary>
			/// Pixel format support stereo buffering.
			/// </summary>
			public bool StereoBuffer;

			/// <summary>
			/// Color bits (without alpha).
			/// </summary>
			public int ColorBits;
			/// <summary>
			/// Depth buffer bits.
			/// </summary>
			public int DepthBits;
			/// <summary>
			/// Stencil buffer bits.
			/// </summary>
			public int StencilBits;
			/// <summary>
			/// Multisample bits.
			/// </summary>
			public int MultisampleBits;

			/// <summary>
			/// sRGB conversion capability.
			/// </summary>
			public bool SRGBCapable;

			/// <summary>
			/// GLX framebuffer configuration (valid only for X11).
			/// </summary>
			public IntPtr XFbConfig;
		}

		/// <summary>
		/// List of pixel format descriptions.
		/// </summary>
		[DebuggerDisplay("PixelFormatCollection({Count} Pixel Formats)")]
		public class PixelFormatCollection : List<PixelFormat>
		{
			#region Render Window Format Filtering

			#region Window Color Bits

			/// <summary>
			/// Get all possible color bit values for rendering on visibile windows.
			/// </summary>
			/// <returns>
			/// It returns a list of integer values suitable for requesting color buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowColorBits()
			{
				return (GetWindowColorBits(-1, -1, -1));
			}

			/// <summary>
			/// Get all possible color bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsMultisample">
			/// A <see cref="System.Int32"/> that specifies the required multisample buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting color buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowColorBits(int bitsMultisample)
			{
				return (GetWindowColorBits(-1, -1, bitsMultisample));
			}

			/// <summary>
			/// Get all possible color bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsDepth">
			/// A <see cref="System.Int32"/> that specifies the required depth buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsMultisample">
			/// A <see cref="System.Int32"/> that specifies the required multisample buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting color buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowColorBits(int bitsDepth, int bitsMultisample)
			{
				return (GetWindowColorBits(bitsDepth, -1, bitsMultisample));
			}

			/// <summary>
			/// Get all possible color bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsDepth">
			/// A <see cref="System.Int32"/> that specifies the required depth buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsStencil">
			/// A <see cref="System.Int32"/> that specifies the required stencil buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsMultisample">
			/// A <see cref="System.Int32"/> that specifies the required multisample buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting color buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowColorBits(int bitsDepth, int bitsStencil, int bitsMultisample)
			{
				List<PixelFormat> windowPixelFormats = this;
				SortedDictionary<int, int> windowColorBits = new SortedDictionary<int,int>();

				// Filter for window rendering type
				windowPixelFormats = FilterPixelFormatByWindow(windowPixelFormats);
				// Filter for buffer bits
				return (GetFormatColorBits(windowPixelFormats, bitsDepth, bitsStencil, bitsMultisample));
			}

			#endregion

			#region Window Depth Bits

			/// <summary>
			/// Get all possible depth bit values for rendering on visibile windows.
			/// </summary>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowDepthBits()
			{
				return (GetWindowDepthBits(-1, -1, -1));
			}

			/// <summary>
			/// Get all possible depth bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowDepthBits(int bitsColor)
			{
				return (GetWindowDepthBits(bitsColor, -1, -1));
			}

			/// <summary>
			/// Get all possible depth bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsMultisample">
			/// A <see cref="System.Int32"/> that specifies the required multisample buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowDepthBits(int bitsColor, int bitsMultisample)
			{
				return (GetWindowDepthBits(bitsColor, -1, bitsMultisample));
			}

			/// <summary>
			/// Get all possible depth bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="colorBits">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsStencil">
			/// A <see cref="System.Int32"/> that specifies the required stencil buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsMultisample">
			/// A <see cref="System.Int32"/> that specifies the required multisample buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowDepthBits(int colorBits, int bitsStencil, int bitsMultisample)
			{
				List<PixelFormat> windowPixelFormats = this;
				SortedDictionary<int, int> windowDepthBits = new SortedDictionary<int,int>();

				// Filter for window rendering type
				windowPixelFormats = FilterPixelFormatByWindow(windowPixelFormats);
				// Filter for buffer bits
				return (GetFormatDepthBits(windowPixelFormats, colorBits, bitsStencil, bitsMultisample));
			}

			#endregion

			#region Window Stencil Bits

			/// <summary>
			/// Get all possible multisample bit values for rendering on visibile windows.
			/// </summary>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowStencilBits()
			{
				return (GetWindowStencilBits(-1, -1, -1));
			}

			/// <summary>
			/// Get all possible multisample bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowStencilBits(int bitsColor)
			{
				return (GetWindowStencilBits(bitsColor, -1, -1));
			}

			/// <summary>
			/// Get all possible multisample bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsDepth">
			/// A <see cref="System.Int32"/> that specifies the required depth buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowStencilBits(int bitsColor, int bitsDepth)
			{
				return (GetWindowStencilBits(bitsColor, bitsDepth, -1));
			}

			/// <summary>
			/// Get all possible multisample bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsDepth">
			/// A <see cref="System.Int32"/> that specifies the required depth buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsMultisample">
			/// A <see cref="System.Int32"/> that specifies the required multisample buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowStencilBits(int bitsColor, int bitsDepth, int bitsMultisample)
			{
				List<PixelFormat> windowPixelFormats = this;
				SortedDictionary<int, int> windowDepthBits = new SortedDictionary<int,int>();

				// Filter for window rendering type
				windowPixelFormats = FilterPixelFormatByWindow(windowPixelFormats);
				// Filter for buffer bits
				return (GetFormatStencilBits(windowPixelFormats, bitsColor, bitsDepth, bitsMultisample));
			}

			#endregion

			#region Window Multisample Bits

			/// <summary>
			/// Get all possible multisample bit values for rendering on visibile windows.
			/// </summary>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowMultisampleBits()
			{
				return (GetWindowMultisampleBits(-1, -1, -1));
			}

			/// <summary>
			/// Get all possible multisample bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowMultisampleBits(int bitsColor)
			{
				return (GetWindowMultisampleBits(bitsColor, -1, -1));
			}

			/// <summary>
			/// Get all possible multisample bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsDepth">
			/// A <see cref="System.Int32"/> that specifies the required depth buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowMultisampleBits(int bitsColor, int bitsDepth)
			{
				return (GetWindowMultisampleBits(bitsColor, bitsDepth, -1));
			}

			/// <summary>
			/// Get all possible multisample bit values for rendering on visibile windows.
			/// </summary>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsDepth">
			/// A <see cref="System.Int32"/> that specifies the required depth buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsStencil">
			/// A <see cref="System.Int32"/> that specifies the required stencil buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetWindowMultisampleBits(int bitsColor, int bitsDepth, int bitsStencil)
			{
				List<PixelFormat> windowPixelFormats = this;
				SortedDictionary<int, int> windowDepthBits = new SortedDictionary<int,int>();

				// Filter for window rendering type
				windowPixelFormats = FilterPixelFormatByWindow(windowPixelFormats);
				// Filter for buffer bits
				return (GetFormatMultisampleBits(windowPixelFormats, bitsColor, bitsStencil, bitsStencil));
			}

			#endregion

			#endregion

			#region Render Buffer Format Filtering



			#endregion

			#region Render PBuffer Format Filtering



			#endregion

			#region Pixel Format Filtering

			#region Combined Bits Filter

			/// <summary>
			/// Get all possible color bit values for rendering on a certain pixel format list.
			/// </summary>
			/// <param name="pFormats">
			/// A <see cref="System.Int32"/> that specifies the initially available pixel formats.
			/// </param>
			/// <param name="bitsDepth">
			/// A <see cref="System.Int32"/> that specifies the required depth buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsStencil">
			/// A <see cref="System.Int32"/> that specifies the required stencil buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsMultisample">
			/// A <see cref="System.Int32"/> that specifies the required multisample buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting color buffer bits.
			/// </returns>
			public IEnumerable<int> GetFormatColorBits(List<PixelFormat> pFormats, int bitsDepth, int bitsStencil, int bitsMultisample)
			{
				List<PixelFormat> windowPixelFormats = this;
				SortedDictionary<int, int> windowColorBits = new SortedDictionary<int,int>();

				// Filter for buffer bits
				if (bitsDepth > 0)
					pFormats = FilterPixelFormatByDepthBits(pFormats, bitsDepth);
				if (bitsStencil > 0)
					pFormats = FilterPixelFormatByDepthBits(pFormats, bitsStencil);
				if (bitsMultisample > 0)
					pFormats = FilterPixelFormatByMultisampleBits(pFormats, bitsMultisample);
				// Find all unique color bits combinations
				foreach (PixelFormat pFormat in windowPixelFormats)
					if (windowColorBits.ContainsKey(pFormat.ColorBits) == false)
						windowColorBits.Add(pFormat.ColorBits, pFormat.ColorBits);

				return (windowColorBits.Keys);
			}

			/// <summary>
			/// Get all possible depth bit values for rendering on a certain pixel format list.
			/// </summary>
			/// <param name="pFormats">
			/// A <see cref="System.Int32"/> that specifies the initially available pixel formats.
			/// </param>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsStencil">
			/// A <see cref="System.Int32"/> that specifies the required stencil buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsMultisample">
			/// A <see cref="System.Int32"/> that specifies the required multisample buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting color buffer bits.
			/// </returns>
			public IEnumerable<int> GetFormatDepthBits(List<PixelFormat> pFormats, int bitsColor, int bitsStencil, int bitsMultisample)
			{
				List<PixelFormat> windowPixelFormats = this;
				SortedDictionary<int, int> windowColorBits = new SortedDictionary<int,int>();

				// Filter for buffer bits
				if (bitsColor > 0)
					pFormats = FilterPixelFormatByColorBits(pFormats, bitsColor);
				if (bitsStencil > 0)
					pFormats = FilterPixelFormatByStencilBits(pFormats, bitsStencil);
				if (bitsMultisample > 0)
					pFormats = FilterPixelFormatByMultisampleBits(pFormats, bitsMultisample);
				// Find all unique color bits combinations
				foreach (PixelFormat pFormat in windowPixelFormats)
					if (windowColorBits.ContainsKey(pFormat.DepthBits) == false)
						windowColorBits.Add(pFormat.DepthBits, pFormat.ColorBits);

				return (windowColorBits.Keys);
			}

			/// <summary>
			/// Get all possible stencil bit values for rendering on a certain pixel format list.
			/// </summary>
			/// <param name="pFormats">
			/// A <see cref="System.Int32"/> that specifies the initially available pixel formats.
			/// </param>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsDepth">
			/// A <see cref="System.Int32"/> that specifies the required depth buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsMultisample">
			/// A <see cref="System.Int32"/> that specifies the required multisample buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting depth buffer bits.
			/// </returns>
			public IEnumerable<int> GetFormatStencilBits(List<PixelFormat> pFormats, int bitsColor, int bitsDepth, int bitsMultisample)
			{
				List<PixelFormat> windowPixelFormats = this;
				SortedDictionary<int, int> windowColorBits = new SortedDictionary<int,int>();

				// Filter for buffer bits
				if (bitsColor > 0)
					pFormats = FilterPixelFormatByColorBits(pFormats, bitsColor);
				if (bitsDepth > 0)
					pFormats = FilterPixelFormatByDepthBits(pFormats, bitsDepth);
				if (bitsMultisample > 0)
					pFormats = FilterPixelFormatByMultisampleBits(pFormats, bitsMultisample);
				// Find all unique color bits combinations
				foreach (PixelFormat pFormat in windowPixelFormats)
					if (windowColorBits.ContainsKey(pFormat.StencilBits) == false)
						windowColorBits.Add(pFormat.StencilBits, pFormat.ColorBits);

				return (windowColorBits.Keys);
			}

			/// <summary>
			/// Get all possible multisample bit values for rendering on a certain pixel format list.
			/// </summary>
			/// <param name="pFormats">
			/// A <see cref="System.Int32"/> that specifies the initially available pixel formats.
			/// </param>
			/// <param name="bitsColor">
			/// A <see cref="System.Int32"/> that specifies the required color buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsDepth">
			/// A <see cref="System.Int32"/> that specifies the required depth buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <param name="bitsStencil">
			/// A <see cref="System.Int32"/> that specifies the required stencil buffer bits. This parameter is ignored in the case is
			/// less or equals to 0.
			/// </param>
			/// <returns>
			/// It returns a list of integer values suitable for requesting multisample buffer bits.
			/// </returns>
			public IEnumerable<int> GetFormatMultisampleBits(List<PixelFormat> pFormats, int bitsColor, int bitsDepth, int bitsStencil)
			{
				List<PixelFormat> windowPixelFormats = this;
				SortedDictionary<int, int> windowColorBits = new SortedDictionary<int,int>();

				// Filter for buffer bits
				if (bitsColor > 0)
					pFormats = FilterPixelFormatByColorBits(pFormats, bitsColor);
				if (bitsDepth > 0)
					pFormats = FilterPixelFormatByDepthBits(pFormats, bitsDepth);
				if (bitsStencil > 0)
					pFormats = FilterPixelFormatByStencilBits(pFormats, bitsStencil);
				// Find all unique color bits combinations
				foreach (PixelFormat pFormat in windowPixelFormats)
					if (windowColorBits.ContainsKey(pFormat.MultisampleBits) == false)
						windowColorBits.Add(pFormat.MultisampleBits, pFormat.ColorBits);

				return (windowColorBits.Keys);
			}

			#endregion

			#region Render Mode Filter

			private List<PixelFormat> FilterPixelFormatByWindow(List<PixelFormat> formats)
			{
				if (formats == null)
					throw new ArgumentNullException("formats");

				return (formats.FindAll(delegate(PixelFormat pFormat) { return (pFormat.RenderWindow == true); }));
			}

			private List<PixelFormat> FilterPixelFormatByBuffer(List<PixelFormat> formats)
			{
				if (formats == null)
					throw new ArgumentNullException("formats");

				return (formats.FindAll(delegate(PixelFormat pFormat) { return (pFormat.RenderBuffer == true); }));
			}

			private List<PixelFormat> FilterPixelFormatByPBuffer(List<PixelFormat> formats)
			{
				if (formats == null)
					throw new ArgumentNullException("formats");

				return (formats.FindAll(delegate(PixelFormat pFormat) { return (pFormat.RenderPBuffer == true); }));
			}

			#endregion

			#region Color/Depth/Stencil/Multisample Bits Filter

			private List<PixelFormat> FilterPixelFormatByColorBits(List<PixelFormat> formats, int bits)
			{
				if (formats == null)
					throw new ArgumentNullException("formats");

				return (formats.FindAll(delegate(PixelFormat pFormat) { return (pFormat.ColorBits == bits); }));
			}

			private List<PixelFormat> FilterPixelFormatByDepthBits(List<PixelFormat> formats, int bits)
			{
				if (formats == null)
					throw new ArgumentNullException("formats");

				return (formats.FindAll(delegate(PixelFormat pFormat) { return (pFormat.DepthBits == bits); }));
			}

			private List<PixelFormat> FilterPixelFormatByStencilBits(List<PixelFormat> formats, int bits)
			{
				if (formats == null)
					throw new ArgumentNullException("formats");

				return (formats.FindAll(delegate(PixelFormat pFormat) { return (pFormat.StencilBits == bits); }));
			}

			private List<PixelFormat> FilterPixelFormatByMultisampleBits(List<PixelFormat> formats, int bits)
			{
				if (formats == null)
					throw new ArgumentNullException("formats");

				return (formats.FindAll(delegate(PixelFormat pFormat) { return (pFormat.MultisampleBits == bits); }));
			}

			#endregion

			#endregion
		}

		/// <summary>
		/// Query available pixel format of a device.
		/// </summary>
		/// <param name="rDevice">
		/// A <see cref="IntPtr"/> representing the device context which defined
		/// the available pixel formats.
		/// </param>
		/// <returns>
		/// </returns>
		public static PixelFormatCollection QueryPixelFormats(IDeviceContext deviceContext)
		{
			return (QueryPixelFormats(deviceContext, CurrentCaps));
		}

		/// <summary>
		/// Query available pixel format of a device.
		/// </summary>
		/// <param name="rDevice">
		/// A <see cref="IntPtr"/> representing the device context which defined
		/// the available pixel formats.
		/// </param>
		/// <param name="ctx">
		/// A <see cref="RenderContext"/> used for querying available pixel formats.
		/// </param>
		/// <returns>
		/// </returns>
		/// <exception cref="ArgumentNullException">
		/// Exception throw if <paramref name="ctx"/> is null.
		/// </exception>
		public static PixelFormatCollection QueryPixelFormats(IDeviceContext deviceContext, RenderContext ctx)
		{
			if (ctx == null)
				throw new ArgumentNullException("ctx");
			return (QueryPixelFormats(deviceContext, ctx.Caps));
		}

		/// <summary>
		/// Query available pixel format of a device.
		/// </summary>
		/// <param name="rDevice">
		/// A <see cref="IntPtr"/> representing the device context which defined
		/// the available pixel formats.
		/// </param>
		/// <param name="caps">
		/// A <see cref="RenderContext.Capabilities"/> that declares which extension are supported by a particoular OpenGL version.
		/// </param>
		/// <returns>
		/// </returns>
		/// <exception cref="ArgumentException">
		/// Exception thrown if <paramref name="rDevice"/> is <see cref="System.IntPtr.Zero"/>.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// Exception throw if <paramref name="caps"/> is null.
		/// </exception>
		public static PixelFormatCollection QueryPixelFormats(IDeviceContext deviceContext, RenderContext.Capabilities caps)
		{
			switch (Environment.OSVersion.Platform) {
				case PlatformID.Win32NT:
				case PlatformID.Win32Windows:
					return (QueryPixelFormatsWgl(deviceContext, caps));
				case PlatformID.Unix:
					return (QueryPixelFormatsGlx(deviceContext, caps));
				default:
					throw new NotSupportedException();
			}
		}

		private static PixelFormatCollection QueryPixelFormatsWgl(IDeviceContext deviceContext, RenderContext.Capabilities caps)
		{
			if (deviceContext == null)
				throw new ArgumentNullException("deviceContext");
			if (caps == null)
				throw new ArgumentNullException("caps");

			WindowsDeviceContext winDeviceContext = (WindowsDeviceContext)deviceContext;
			PixelFormatCollection pFormats = new PixelFormatCollection();
			List<int> pfAttributesCodes = new List<int>(12);
			int[] pfAttributesValue;

			// Minimum requirements
			pfAttributesCodes.Add(Wgl.SUPPORT_OPENGL_ARB);		// Required to be Gl.TRUE
			pfAttributesCodes.Add(Wgl.ACCELERATION_ARB);		// Required to be Wgl.FULL_ACCELERATION or Wgl.ACCELERATION_ARB
			pfAttributesCodes.Add(Wgl.PIXEL_TYPE_ARB);
			// Buffer destination
			pfAttributesCodes.Add(Wgl.DRAW_TO_WINDOW_ARB);
			pfAttributesCodes.Add(Wgl.DRAW_TO_BITMAP_ARB);
			pfAttributesCodes.Add(Wgl.DRAW_TO_PBUFFER_ARB);
			// Multiple buffers
			pfAttributesCodes.Add(Wgl.DOUBLE_BUFFER_ARB);
			pfAttributesCodes.Add(Wgl.SWAP_METHOD_ARB);
			pfAttributesCodes.Add(Wgl.STEREO_ARB);
			// Pixel description
			pfAttributesCodes.Add(Wgl.COLOR_BITS_ARB);
			pfAttributesCodes.Add(Wgl.DEPTH_BITS_ARB);
			pfAttributesCodes.Add(Wgl.STENCIL_BITS_ARB);
			// Multisample extension
			if (caps.Multisample.Supported == true) {
				pfAttributesCodes.Add(Wgl.SAMPLE_BUFFERS_ARB);
				pfAttributesCodes.Add(Wgl.SAMPLES_ARB);
			}
#if false
			// Framebuffer sRGB extension
			if ((caps.FramebufferSRGB.Supported == true) || (caps.FramebufferSRGB_EXT.Supported == true)) {
				pfAttributesCodes.Add(Wgl.FRAMEBUFFER_SRGB_CAPABLE_ARB);
			}
#endif

			pfAttributesValue = new int[pfAttributesCodes.Count];
			for (int pFormatIndex = 1;; pFormatIndex++) {
				PixelFormat pFormat;

				if (Wgl.GetPixelFormatAttribARB(winDeviceContext.DeviceContext, pFormatIndex, 0, (uint)pfAttributesCodes.Count, pfAttributesCodes.ToArray(), pfAttributesValue) == false) {
					Debug.Assert(pFormats.Count > 0, "wrong pixel format attribute list");
					break;	// All pixel format are queried
				}

				// Check minimum requirements
				if (pfAttributesValue[0] != Gl.TRUE)
					continue;		// No OpenGL support
				if (pfAttributesValue[1] != Wgl.FULL_ACCELERATION_ARB)
					continue;		// No hardware acceleration
				if (pfAttributesValue[2] != Wgl.TYPE_RGBA_ARB)
					continue;		// Ignored pixel type

				// Collect pixel format attributes
				pFormat.FormatIndex = pFormatIndex;

				pFormat.RgbaUnsigned = pfAttributesValue[2] == Wgl.TYPE_RGBA_ARB;
				pFormat.RgbaFloat = pfAttributesValue[2] == Wgl.TYPE_RGBA_FLOAT_ARB;

				pFormat.RenderWindow = pfAttributesValue[3] == Gl.TRUE;
				pFormat.RenderBuffer = pfAttributesValue[4] == Gl.TRUE;
				pFormat.RenderPBuffer = pfAttributesValue[5] == Gl.TRUE;

				pFormat.DoubleBuffer = pfAttributesValue[6] == Gl.TRUE;
				pFormat.SwapMethod = pfAttributesValue[7];
				pFormat.StereoBuffer = pfAttributesValue[8] == Gl.TRUE;

				pFormat.ColorBits = pfAttributesValue[9];
				pFormat.DepthBits = pfAttributesValue[10];
				pFormat.StencilBits = pfAttributesValue[11];

				if (caps.Multisample.Supported == true) {
					// pfAttributesValue[12] ? What about multiple sample buffers?
					pFormat.MultisampleBits = pfAttributesValue[13];
				} else
					pFormat.MultisampleBits = 0;

#if false
                XXX Problems with 2.1 contextes
				if ((caps.FramebufferSRGB.Supported == true) || (caps.FramebufferSRGB_EXT.Supported == true)) {
					pFormat.SRGBCapable = pfAttributesValue[13] != 0;
				} else
#endif
                pFormat.SRGBCapable = false;
				pFormat.XFbConfig = IntPtr.Zero;

				pFormats.Add(pFormat);
			}

			return (pFormats);
		}

		private static PixelFormatCollection QueryPixelFormatsGlx(IDeviceContext deviceContext, RenderContext.Capabilities caps)
		{
			if (deviceContext == null)
				throw new ArgumentNullException("deviceContext");
			if (caps == null)
				throw new ArgumentNullException("caps");

			XServerDeviceContext x11DeviceContext = (XServerDeviceContext)deviceContext;
			PixelFormatCollection pFormats = new PixelFormatCollection();
			int configsCount = 0;

			unsafe {
				IntPtr *configs = Glx.GetFBConfigs(x11DeviceContext.Display, x11DeviceContext.Screen, out configsCount);

				for (int i = 0; i < configsCount; i++) {
					IntPtr configId = configs[i];
					int err, renderType, attribValue;

					// Requires RGBA configuration
					err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.RENDER_TYPE, out renderType);
					if (err != 0)
						throw new InvalidOperationException();
					if ((renderType & Glx.RGBA_BIT) == 0)
						continue;		// Ignore indexed visuals

					// Do not choose configurations with some caveat
					err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.CONFIG_CAVEAT, out attribValue);
					if (attribValue == Glx.SLOW_CONFIG)
						continue;

					PixelFormat pixelFormat = new PixelFormat();

					pixelFormat.XFbConfig = configId;

					pixelFormat.RgbaUnsigned = (renderType & Glx.RGBA_FLOAT_BIT_ARB) == 0;;
					pixelFormat.RgbaFloat = (renderType & Glx.RGBA_FLOAT_BIT_ARB) != 0;

					err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.DRAWABLE_TYPE, out attribValue);
					if (err != 0)
						throw new InvalidOperationException("unable to get DRAWABLE_TYPE from framebuffer configuration");

					pixelFormat.RenderWindow = (attribValue & Glx.WINDOW_BIT) != 0;
					pixelFormat.RenderBuffer = false;
					pixelFormat.RenderPBuffer = (attribValue & Glx.PBUFFER_BIT) != 0;

					err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.FBCONFIG_ID, out pixelFormat.FormatIndex);
					if (err != 0)
						throw new InvalidOperationException("unable to get FBCONFIG_ID from framebuffer configuration");

					err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.BUFFER_SIZE, out pixelFormat.ColorBits);
					if (err != 0)
						throw new InvalidOperationException("unable to get BUFFER_SIZE from framebuffer configuration");

					err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.DEPTH_SIZE, out pixelFormat.DepthBits);
					if (err != 0)
						throw new InvalidOperationException("unable to get DEPTH_SIZE from framebuffer configuration");

					err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.STENCIL_SIZE, out pixelFormat.StencilBits);
					if (err != 0)
						throw new InvalidOperationException("unable to get STENCIL_SIZE from framebuffer configuration");

					if (caps.Multisample.Supported) {
						int hasMultisample = 0;

						err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.SAMPLE_BUFFERS, out hasMultisample);
						if (err != 0)
							throw new InvalidOperationException("unable to get SAMPLE_BUFFERS from framebuffer configuration");

						if (hasMultisample != 0) {
							pixelFormat.MultisampleBits = 0;
							err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.SAMPLES, out pixelFormat.MultisampleBits);
							if (err != 0)
								throw new InvalidOperationException("unable to get SAMPLES from framebuffer configuration");
						} else
							pixelFormat.MultisampleBits = 0;
					}

					err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.DOUBLEBUFFER, out attribValue);
					if (err != 0)
						throw new InvalidOperationException("unable to get DOUBLEBUFFER from framebuffer configuration");
					pixelFormat.DoubleBuffer = attribValue != 0;

					err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.STEREO, out attribValue);
					if (err != 0)
						throw new InvalidOperationException("unable to get STEREO from framebuffer configuration");
					pixelFormat.StereoBuffer = attribValue != 0;

					if (caps.FramebufferSRGB.Supported) {
						err = Glx.GetFBConfigAttrib(x11DeviceContext.Display, configId, Glx.FRAMEBUFFER_SRGB_CAPABLE_ARB, out attribValue);
						if (err != 0)
							throw new InvalidOperationException("unable to get FRAMEBUFFER_SRGB_CAPABLE_ARB from framebuffer configuration");
						pixelFormat.SRGBCapable = attribValue != 0;
					} else
						pixelFormat.SRGBCapable = false;

					pFormats.Add(pixelFormat);
				}
			}

			return (pFormats);
		}

		#endregion

		#region Object Name Space Sharing

		#region Object Class Sharing

		/// <summary>
		/// Property that specify whether this RenderContext is sharing texture objects.
		/// </summary>
		public bool ShareTextureObjects { get { return (IsSharedObjectClass(Texture.TextureObjectClass)); } }

		/// <summary>
		/// Property that specify whether this RenderContext is sharing shader objects.
		/// </summary>
		public bool ShareShaderObjects { get { return (IsSharedObjectClass(ShaderObject.ShaderObjectClass)); } }

		/// <summary>
		/// Property that specify whether this RenderContext is sharing shader program objects.
		/// </summary>
		public bool ShareShaderProgramObjects { get { return (IsSharedObjectClass(ShaderProgram.ShaderProgramObjectClass)); } }

		/// <summary>
		/// Property that specify whether this RenderContext is sharing render buffer objects.
		/// </summary>
		public bool ShareRenderBufferObjects { get { return (IsSharedObjectClass(RenderBuffer.RenderBufferObjectClass)); } }

		/// <summary>
		/// Property that specify whether this RenderContext is sharing render buffer objects.
		/// </summary>
		public bool ShareFramebufferObjects { get { return (IsSharedObjectClass(RenderBuffer.RenderBufferObjectClass)); } }

		/// <summary>
		/// Property that specify whether this RenderContext is sharing vertex buffer objects.
		/// </summary>
		public bool ShareVertexBufferObjects { get { return (IsSharedObjectClass(BufferObject.BufferObjectClass)); } }

		/// <summary>
		/// Property that specify whether this RenderContext is sharing vertex array objects.
		/// </summary>
		public bool ShareVertexArrayObjects { get { return (IsSharedObjectClass(VertexArrayObject.VertexArrayObjectClass)); } }

		#endregion

		/// <summary>
		/// RenderContext object name space.
		/// </summary>
		internal Guid ObjectNameSpace { get { return (mObjectNameSpace); } }

		/// <summary>
		/// Property that specify whether this RenderContext is sharing a specific object class.
		/// </summary>
		/// <param name="class"></param>
		/// <returns></returns>
		internal bool IsSharedObjectClass(Guid @class)
		{
			return ((mSharedObjectClasses != null) && (mSharedObjectClasses.Contains(@class)));
		}

		/// <summary>
		/// Execute a benchmark to determine whether this RenderContext can share various object.
		/// </summary>
		/// <param name="rContextShare">
		/// A <see cref="RenderContext"/> sharing with this RenderContext.
		/// </param>
		private void TestSharingObjects(RenderContext rContextShare)
		{
			if (rContextShare == null)
				throw new ArgumentNullException("rContextShare");
			if (IsCurrent() == false)
				throw new InvalidOperationException("not current");

			#region Create Objects

			// Create objects on this RenderContext
			uint texture = 0;
			uint shader = 0;
			uint shaderProgram = 0;
			uint renderBuffer = 0;
			uint framebuffer = 0;
			uint vertexBuffer = 0;
			uint vertexArray = 0;

			#region Textures

			if (Caps.TextureObject.Supported == true) {
				// Generate texture name
				Gl.GenTextures(1, out texture);
				// Ensure existing texture object
				Gl.BindTexture(Gl.TEXTURE_2D, texture);
				Gl.BindTexture(Gl.TEXTURE_2D, 0);
				// Self test
				if (Gl.IsTexture(texture) == false)
					throw new NotSupportedException();
			}

			#endregion

			#region Shader

			if (Caps.ShaderObjects.Supported == true) {
				// Generate shader object name
				shader = Gl.CreateShader(Gl.VERTEX_SHADER);
				// Self test
				if (Gl.IsShader(shader) == false)
					throw new NotSupportedException();
			}

			#endregion

			#region Shader Program

			if (Caps.VertexShader.Supported == true) {
				// Generate shader program object name
				shaderProgram = Gl.CreateProgram();
				// Self test
				if (Gl.IsProgram(shaderProgram) == false)
					throw new NotSupportedException();
			}

			#endregion

			#region Render Buffer

			if (Caps.FrambufferObject.Supported == true) {
				// Generate shader program object name
				Gl.GenRenderbuffer(1, out renderBuffer);
				// Ensure existing render buffer
				Gl.BindRenderbuffer(Gl.RENDERBUFFER, renderBuffer);
				Gl.BindRenderbuffer(Gl.RENDERBUFFER, 0);
				// Self test
				if (Gl.IsRenderbuffer(renderBuffer) == false)
					throw new NotSupportedException();
			}

			#endregion

			#region Framebuffer

			if (Caps.FrambufferObject.Supported == true) {
				// Generate framebuffer name
				Gl.GenFramebuffers(1, out framebuffer);
				// Ensure existing object
				Gl.BindFramebuffer(Gl.FRAMEBUFFER, framebuffer);
				Gl.BindFramebuffer(Gl.FRAMEBUFFER, 0);
				// Self test
				if (Gl.IsFramebuffer(framebuffer) == false)
					throw new NotSupportedException();
			}

			#endregion

			#region Vertex Buffer

			if (Caps.VertexBufferObject.Supported == true) {
				// Generate buffer name
				Gl.GenBuffers(1, out vertexBuffer);
				// Ensure existing object
				Gl.BindBuffer(Gl.ARRAY_BUFFER, vertexBuffer);
				Gl.BindBuffer(Gl.ARRAY_BUFFER, 0);
				// Self test
				if (Gl.IsBuffer(vertexBuffer) == false)
					throw new NotSupportedException();
			}

			#endregion

			#region Vertex Array

			if (Caps.VertexArrayObject.Supported == true) {
				// Generate buffer name
				Gl.GenVertexArrays(1, out vertexArray);
				// Ensure existing object
				Gl.BindVertexArray(vertexArray);
				Gl.BindVertexArray(0);
				// Self test
				if (Gl.IsVertexArray(vertexArray) == false)
					throw new NotSupportedException();
			}

			#endregion

			#endregion

			// Make current sharing context
			rContextShare.MakeCurrent(true);

			#region Test Object Sharing

			// Create dictionary
			mSharedObjectClasses = new ListDictionary();

			if ((texture != 0) && (Gl.IsTexture(texture) == true))
				mSharedObjectClasses.Add(Texture.TextureObjectClass, Texture.TextureObjectClass);

			if ((shader != 0) && (Gl.IsShader(shader) == true))
				mSharedObjectClasses.Add(ShaderObject.ShaderObjectClass, ShaderObject.ShaderObjectClass);

			if ((shaderProgram != 0) && (Gl.IsProgram(shaderProgram) == true))
				mSharedObjectClasses.Add(ShaderProgram.ShaderProgramObjectClass, ShaderProgram.ShaderProgramObjectClass);

			if ((renderBuffer != 0) && (Gl.IsRenderbuffer(renderBuffer) == true))
				mSharedObjectClasses.Add(RenderBuffer.RenderBufferObjectClass, RenderBuffer.RenderBufferObjectClass);

			if ((vertexBuffer != 0) && (Gl.IsBuffer(vertexBuffer) == true))
				mSharedObjectClasses.Add(BufferObject.BufferObjectClass, BufferObject.BufferObjectClass);

			if ((vertexArray != 0) && (Gl.IsVertexArray(vertexArray) == true))
				mSharedObjectClasses.Add(VertexArrayObject.VertexArrayObjectClass, VertexArrayObject.VertexArrayObjectClass);

			#endregion

			#region Delete Objects

			// Texture
			if (texture != 0)
				Gl.DeleteTextures(1, new uint[] { texture });
			// Shader
			if (shader != 0)
				Gl.DeleteShader(shader);
			// Shader program
			if (shaderProgram != 0)
				Gl.DeleteProgram(shaderProgram);
			// Render buffer
			if (renderBuffer != 0)
				Gl.DeleteRenderbuffer(1, new uint[] { renderBuffer });
			// Framebuffer
			if (framebuffer != 0)
				Gl.DeleteFramebuffers(1, new uint[] { framebuffer });
			// Vertex buffer
			if (vertexBuffer != 0)
				Gl.DeleteBuffers(1, new uint[] { vertexBuffer });
			// Vertex array
			if (vertexArray != 0)
				Gl.DeleteVertexArrays(1, new uint[] { vertexArray });

			#endregion

			// Because sharing is transitive, the tested object sharing is managed also by the sharing context
			rContextShare.mSharedObjectClasses = mSharedObjectClasses;

			// Make current this context
			MakeCurrent(true);
		}

		/// <summary>
		/// Object name space identifier.
		/// </summary>
		private Guid mObjectNameSpace = Guid.Empty;

		/// <summary>
		/// Sharing object classes.
		/// </summary>
		/// <remarks>
		/// This dictionary determine which object classes can be shared within this RenderContext object name
		/// space.
		/// </remarks>
		private ListDictionary mSharedObjectClasses;

		#endregion

		#region Object Name Space Services

		/// <summary>
		/// Garbage service used to delete objects.
		/// </summary>
		/// <remarks>
		/// This service is mandatory.
		/// </remarks>
		private RenderGarbageService mGarbageService = null;

		/// <summary>
		/// Shader object cache.
		/// </summary>
		private ShaderCacheService mShaderCacheService = null;

		#endregion

		#region Context Currency

		/// <summary>
		/// Set this RenderContext current/uncurrent on current device.
		/// </summary>
		/// <param name="flag">
		/// A <see cref="System.Boolean"/> that specifies the currency of this RenderContext on the
		/// device context used to create this RenderContext.
		/// </param>
		/// <remarks>
		/// <para>
		/// The current device is defined as follow:
		/// - If this RenderContext has never been current on a thread, the current device context is the one specified at construction time. In the case
		///   this RenderContext was not constructed specifying a device context, the common device context is the used one. Otherwise...
		/// - The last device context used to make current this context, by calling <see cref="MakeCurrent(System.IntPtr,System.Boolean)"/> or 
		///   <see cref="MakeCurrent(System.Boolean)"/>.
		/// </para>
		/// </remarks>
		/// <exception cref="ObjectDisposedException">
		/// Exception throw if this RenderContext has been disposed. Once the RenderContext has been disposed it cannot be current again.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// Exception throw if this RenderContext cannot be made current/uncurrent on the device context specified at construction time.
		/// </exception>
		public void MakeCurrent(bool flag)
		{
			if (mCurrentDeviceContext == null)
				throw new ObjectDisposedException("no context associated with this RenderContext");

			// Already current?
			if (IsCurrent())
				return;

			MakeCurrent(mCurrentDeviceContext, flag);
		}

		/// <summary>
		/// Set this RenderContext current/uncurrent on device different from the one specified at construction time.
		/// </summary>
		/// <param name="deviceContext">
		/// A <see cref="IDeviceContext"/> that specifies the device context involved.
		/// </param>
		/// <param name="flag">
		/// A <see cref="System.Boolean"/> that specifies the currency of this RenderContext on the
		/// device context <paramref name="rDevice"/>.
		/// </param>
		/// <exception cref="ArgumentException">
		/// Exception throw in the case <paramref name="rDevice"/> is <see cref="System.IntPtr.Zero"/>.
		/// </exception>
		/// <exception cref="ObjectDisposedException">
		/// Exception throw if this RenderContext has been disposed. Once the RenderContext has been disposed it cannot be current again.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// Exception throw if this RenderContext cannot be made current/uncurrent on the device context specified by <paramref name="rDevice"/>.
		/// </exception>
		public void MakeCurrent(IDeviceContext deviceContext, bool flag)
		{
			if (deviceContext == null)
				throw new ArgumentNullException("deviceContext");
			if (mDeviceContext == null)
				throw new ObjectDisposedException("no context associated with this RenderContext");

			int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;

			if (flag) {
				// Make this context current on device
				if (Gl.MakeContextCurrent(deviceContext, mRenderContext) == false)
					throw new InvalidOperationException("context cannot be current because error " + Marshal.GetLastWin32Error());

				// Cache current device context
				mCurrentDeviceContext = deviceContext;
				// Set current context on this thread (only on success)
				lock (sRenderThreadsLock) {
					sRenderThreads[threadId] = this;
				}
			} else {
				// Make this context uncurrent on device
				bool res = Gl.MakeContextCurrent(deviceContext, mRenderContext);

				// Reset current context on this thread (even on error)
				lock (sRenderThreadsLock) {
					sRenderThreads[threadId] = null;
				}

				if (res == false)
					throw new InvalidOperationException("context cannot be uncurrent because error " + Marshal.GetLastWin32Error());
			}
		}

		/// <summary>
		/// Determine whether rendering context is current to the calling thread.
		/// </summary>
		/// <returns>
		/// It returns true if the render context is current on the calling thread, otherwise it returns false.
		/// </returns>
		public bool IsCurrent()
		{
			int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;

			lock (sRenderThreadsLock) {
				RenderContext currentThreadContext;

				// Get context registered as current to the current thread
				if (sRenderThreads.TryGetValue(threadId, out currentThreadContext) == false)
					return (false);
				// Test identification corrispodence
				if (currentThreadContext != null)
					return (currentThreadContext.mRenderContextId == mRenderContextId);
				else
					return (false);
			}
		}

		/// <summary>
		/// Get the current RenderContext on the calling thread.
		/// </summary>
		/// <returns>
		/// It returns any RenderContext current on the calling thread. In the case no context is current, it returns null.
		/// </returns>
		public static RenderContext GetCurrentContext()
		{
			int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;

			lock (sRenderThreadsLock) {
				RenderContext currentThreadContext;
                
				if (sRenderThreads.TryGetValue(threadId, out currentThreadContext) == false)
					return (null);
				
				return (currentThreadContext);
			}
		}
		
		/// <summary>
		/// Flush RenderContext commands.
		/// </summary>
		/// <remarks>
		/// Flushing rendering operations is automatically done by the system when it is more approriate. There's no need to
		/// call it manually.
		/// </remarks>
		public void Flush()
		{
			Gl.Flush();
		}

		/// <summary>
		/// Common (hidden) window used for getting device context without creating a new window.
		/// </summary>
		internal static System.Windows.Forms.Form HiddenWindow;

		/// <summary>
		/// Device context handle referred by RenderContext at construction time.
		/// </summary>
		private IDeviceContext mDeviceContext;

		/// <summary>
		/// Device context handle referred by RenderContext when has became current.
		/// </summary>
		/// <remarks>
		/// <para>
		/// It could be different from <see cref="mDeviceContext"/>. It will be used internally to make current this RenderContext
		/// on the correct device context.
		/// </para>
		/// <para>
		/// If its value is <see cref="System.IntPtr.Zero"/>, it means that this RenderContext has never been current on a thread.
		/// </para>
		/// </remarks>
		private IDeviceContext mCurrentDeviceContext;

		/// <summary>
		/// Flag indicating whether <see cref="mDeviceContext"/> is a device context for the entire screen. This means that
		/// no <see cref="RenderWindow"/> instance will release the device context, so this RenderContext instance will
		/// take care of releasing it.
		/// </summary>
		private readonly bool mCommonDeviceContext;

		/// <summary>
		/// Thread identifier which has created the device context. This field is meaninfull only in the case <see cref="mCommonDeviceContext"/> is
		/// true.
		/// </summary>
		/// <remarks>
		/// This value is used in the case the device context is the one offered by <see cref="HiddenWindow"/>. At Dispose time, if the calling thread
		/// identifier is not the same of the value of this field, an exception will be thrown becuase device context shall be released by the same
		/// thread which has allocated it.
		/// </remarks>
		private int mDeviceContextThreadId;

		/// <summary>
		/// Thread identifier which has created this RenderContext.
		/// </summary>
		/// <remarks>
		/// This information is used for checking whether a context can be shared with another one: contextes must be created
		/// by the same thread. This would avoid an InvalidOperationException caused by constructors.
		/// </remarks>
		private int mRenderContextThreadId;

		/// <summary>
		/// Rendering context handle.
		/// </summary>
		private IntPtr mRenderContext = IntPtr.Zero;

		/// <summary>
		/// Unique identifier of this RenderContext.
		/// </summary>
		private Guid mRenderContextId = Guid.NewGuid();

		/// <summary>
		/// Map between process threads and current render context.
		/// </summary>
		private static readonly Dictionary<int, RenderContext> sRenderThreads = new Dictionary<int,RenderContext>();

		/// <summary>
		/// Object used for synchronizing <see cref="sRenderThreads"/> accesses.
		/// </summary>
		private static readonly object sRenderThreadsLock = new object();

		#endregion

		#region State Set & Stack

		/// <summary>
		/// Current render state set.
		/// </summary>
		public RenderStateSet CurrentState
		{
			get { return (mRenderStateSetStack.Last.Value); }
		}

		/// <summary>
		/// Reset the current context state
		/// </summary>
		public void ResetState()
		{
			RenderStateSet defaultState = mRenderStateSetStack.First.Value;

			if (IsCurrent() == false)
				throw new InvalidOperationException("ctx");

			Debug.Assert(mRenderStateSetStack.Count == 1);

			// Clear stack (keep only the default state)
			mRenderStateSetStack.Clear();
			mRenderStateSetStack.AddFirst(RenderStateSet.GetDefaultSet());
			// Apply default state
			defaultState.Apply(this);
		}

		/// <summary>
		/// Apply a RenderState set to the current state vector.
		/// </summary>
		/// <param name="renderStateSet">
		/// A <see cref="RenderStateSet"/> that specify the current state to apply.
		/// </param>
		/// <remarks>
		/// If <paramref name="renderStateSet"/> doesn't specify a specific state, it will be derived from the current one.
		/// </remarks>
		public void ApplyState(RenderStateSet renderStateSet)
		{
			ApplyState(renderStateSet, null);
		}

		/// <summary>
		/// Apply a RenderState set to the current state vector.
		/// </summary>
		/// <param name="renderStateSet"></param>
		/// <param name="shaderProgram"></param>
		public void ApplyState(RenderStateSet renderStateSet, ShaderProgram shaderProgram)
		{
			RenderStateSet currentStateSet = mRenderStateSetStack.Last.Value;
			
			if (renderStateSet == null)
				throw new ArgumentNullException("renderStateSet");
			if (IsCurrent() == false)
				throw new InvalidOperationException("ctx");

			currentStateSet = renderStateSet.Merge(this, shaderProgram, currentStateSet);

			mRenderStateSetStack.RemoveLast();
			mRenderStateSetStack.AddLast(currentStateSet);
		}

		/// <summary>
		/// Push <see cref="CurrentState"/> onto the state set stack.
		/// </summary>
		public void PushState()
		{
			if (IsCurrent() == false)
				throw new InvalidOperationException("not current");

			mRenderStateSetStack.AddLast(CurrentState.Copy());
		}

		/// <summary>
		/// Pop <see cref="CurrentState"/> from the state set stack, and switch to the lower one.
		/// </summary>
		public void PopState()
		{
			if (IsCurrent() == false)
				throw new InvalidOperationException("not current");
			if (mRenderStateSetStack.Count == 1 /* The default one */)
				throw new InvalidOperationException("render state stack empty");

			// Remove current state
			RenderStateSet currentState = mRenderStateSetStack.Last.Value;
			mRenderStateSetStack.RemoveLast();

			// Restore previous state (apply only changed context states)
			RenderStateSet previousState = mRenderStateSetStack.Last.Value;

			foreach (RenderState renderState in currentState.States) {
				if (renderState.IsContextBound == true) {
					Debug.Assert(previousState.IsDefinedState(renderState.Id), "context-bound state no defined in default state");
					previousState[renderState.Id].ApplyState(this, null);
				}
			}
		}

		/// <summary>
		/// Stack of render state set.
		/// </summary>
		/// <remarks>
		/// <para>
		/// This stack keep track of the current render state vector.
		/// </para>
		/// </remarks>
		private readonly LinkedList<RenderStateSet> mRenderStateSetStack = new LinkedList<RenderStateSet>();

		#endregion

		#region Projection Matrix & Stack

		/// <summary>
		/// Projection matrix.
		/// </summary>
		public ProjectionMatrix Projection
		{
			get { return (mProjection); }
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");
				mProjection = value;
			}
		}

		/// <summary>
		/// Push current projection onto the relative stack.
		/// </summary>
		public void PushProjection()
		{
			// Push current projection onto the relative stack.
			mProjectionStack.Push((ProjectionMatrix)mProjection.Clone());
		}

		/// <summary>
		/// Replace current projection matrices with the previously pushed one.
		/// </summary>
		public void PopProjection()
		{
			if (mProjectionStack.Count == 0)
				throw new InvalidOperationException("empty projection stack");

			// Pop projection matrices
			mProjection = mProjectionStack.Pop();
		}

		/// <summary>
		/// Projection transformation context.
		/// </summary>
		private ProjectionMatrix mProjection = new ProjectionMatrix();

		/// <summary>
		/// Projection transnformation stack.
		/// </summary>
		private readonly Stack<ProjectionMatrix> mProjectionStack = new Stack<ProjectionMatrix>();

		#endregion

		#region Model Matrix & Stack

		/// <summary>
		/// Get or set the model matrix used for rendering.
		/// </summary>
		/// <remarks>
		/// <para>
		/// The model matrix is usually used to transform drawn vertices. This property is used by the scene graph
		/// as the OpenGL fixed-pipeline modelview matrix.
		/// </para>
		/// </remarks>
		public ModelMatrix Model
		{
			get { return (mModel); }
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");
				mModel = value;
			}
		}

		/// <summary>
		/// Push current model onto the relative stack.
		/// </summary>
		public void PushModel()
		{
			// Push current model onto the relative stack.
			mModelStack.Push((ModelMatrix)mModel.Clone());
		}

		/// <summary>
		/// Replace current model matrices with the previously pushed one.
		/// </summary>
		public void PopModel()
		{
			if (mModelStack.Count == 0)
				throw new InvalidOperationException("empty model stack");

			// Pop model matrices
			mModel = mModelStack.Pop();
		}

		/// <summary>
		/// Current model stack depth.
		/// </summary>
		public uint ModelStackDepth { get { return ((uint) mModelStack.Count); }}

		/// <summary>
		/// Model transformation context.
		/// </summary>
		/// <remarks>
		/// Initially the model transform context is set to identity.
		/// </remarks>
		private ModelMatrix mModel = new ModelMatrix();

		/// <summary>
		/// Model transformation stack.
		/// </summary>
		/// <remarks>
		/// Initially the model transformation track is empty.
		/// </remarks>
		private readonly Stack<ModelMatrix> mModelStack = new Stack<ModelMatrix>();

		#endregion

		#region Debugging

		/// <summary>
		/// Flag indicating whether debugging is enabled.
		/// </summary>
		internal bool DebugEnabled { get { return (mDebugEnabled); }}

		/// <summary>
		/// Flag indicating whether debugging is enabled.
		/// </summary>
		private bool mDebugEnabled = true;

		#endregion

		#region Selection Buffer Management

		/// <summary>
		/// Allocate rendering selection buffer.
		/// </summary>
		/// <param name="size"></param>
		void AllocateSelectionBuffer(int size)
		{
//#if !OPENGL_3
//			if (mSelectBufferSize != size) {
//				// Store selection buffer size
//				mSelectBufferSize = size;
//				// Allocate selection buffer
//				mSelectBuffer = new int[size];
//			}
//			/* Allocate selection buffer */
//			Gl.SelectBuffer(mSelectBufferSize, mSelectBuffer);
//			Debug.Assert(CheckErrors() == true);
//#endif
		}

		/// <summary>
		/// Get RenderContext selection buffer data.
		/// </summary>
		/// <returns></returns>
		int[] GetSelectionBuffer()
		{
			return (mSelectBuffer);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		int GetSelectionBufferSize()
		{
			return (mSelectBufferSize);
		}
		
		/// <summary>
		/// Buffer used for selection.
		/// </summary>
		private int[] mSelectBuffer = null;
		/// <summary>
		/// Selection buffer size (number of elements in mSelectBuffer).
		/// </summary>
		private int mSelectBufferSize = 0;

		#endregion

		#region Logging

		/// <summary>
		/// Logger of this class.
		/// </summary>
		private static readonly ILogger sLog = Log.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

		#endregion

		#region IDisposable Implementation

		/// <summary>
		/// Finalizer.
		/// </summary>
		~RenderContext()
		{
			Dispose(false);
		}

		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or resetting managed/unmanaged resources.
		/// </summary>
		/// <param name="disposing">
		/// </param>
		/// <remarks>
		/// This method shall be called by the same thread which has created this RenderContext, but only in the case the following
		/// constructors were called:
		/// - @ref RenderContext::RenderContext()
		/// </remarks>
		/// <exception cref="InvalidOperationException">
		/// Exception throw if this RenderContext has not been disposed before finalization.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// Exception throw if it's not possible to release correctly the OpenGL context related to this RenderContext.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// Exception throw if the current thread is not the one which has constructed this RenderContext.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// Exception throw if it's not possible to release correctly the GDI device context related to this RenderContext.
		/// </exception>
		private void Dispose(bool disposing)
		{
			if ((disposing == false) && (mRenderContext != IntPtr.Zero))
				throw new InvalidOperationException("not disposed on finalization");

			// Remove shader cache service
			if (mShaderCacheService != null) {
				mShaderCacheService.UnbindObjectNameSpace();
				mShaderCacheService = null;
			}
			// Remove garbage service
			if (mGarbageService != null) {
				mGarbageService.UnbindObjectNameSpace();
				mGarbageService = null;
			}

			if (disposing == true) {
				// Dispose unmanaged resources
				if (mRenderContext != IntPtr.Zero) {
					if (Wgl.DeleteContext(mRenderContext) == false)
						throw new InvalidOperationException("unable to release OpenGL context");
					mRenderContext = IntPtr.Zero;
				}
				if ((mDeviceContext != null) && (mCommonDeviceContext == true)) {
					if (mDeviceContextThreadId != System.Threading.Thread.CurrentThread.ManagedThreadId)
						throw new InvalidOperationException("disposing on a different thread context");
					mDeviceContext.Release();
				}
				mDeviceContext = null;

				// Remove context from the current ones
				int threadId = 0;
				bool threadCurrentFound = false;

				lock (sRenderThreadsLock) {
					foreach (KeyValuePair<int, RenderContext> pair in sRenderThreads) {
						if (Object.ReferenceEquals(pair.Value, this) == true) {
							threadId = pair.Key;
							threadCurrentFound = true;
							break;
						}
					}
				}

				if (threadCurrentFound == true)
					sRenderThreads[threadId] = null;
			}
		}

		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		/// </summary>
		/// <exception cref="InvalidOperationException">
		/// Exception throw if it's not possible to release correctly the OpenGL context related to this RenderContext.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// Exception throw if the current thread is not the one which has constructed this RenderContext.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// Exception throw if it's not possible to release correctly the GDI device context related to this RenderContext.
		/// </exception>
		public void Dispose()
		{
			GC.SuppressFinalize(this);
			Dispose(true);
		}

		#endregion
	}
}
